{"id":"bc586ed409dd403c","repo":"pallets/flask","slug":"the-session-is-unavailable-because-no-secret-key-w","errorCode":null,"errorMessage":"The session is unavailable because no secret key was set.  Set the secret_key on the application to something unique and secret.","messagePattern":"The session is unavailable because no secret key was set\\.  Set the secret_key on the application to something unique and secret\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"src/flask/sessions.py","lineNumber":90,"sourceCode":"\n    def __init__(\n        self,\n        initial: c.Mapping[str, t.Any] | None = None,\n    ) -> None:\n        def on_update(self: te.Self) -> None:\n            self.modified = True\n\n        super().__init__(initial, on_update)\n\n\nclass NullSession(SecureCookieSession):\n    \"\"\"Class used to generate nicer error messages if sessions are not\n    available.  Will still allow read-only access to the empty session\n    but fail on setting.\n    \"\"\"\n\n    def _fail(self, *args: t.Any, **kwargs: t.Any) -> t.NoReturn:\n        raise RuntimeError(\n            \"The session is unavailable because no secret \"\n            \"key was set.  Set the secret_key on the \"\n            \"application to something unique and secret.\"\n        )\n\n    __setitem__ = __delitem__ = clear = pop = popitem = update = setdefault = _fail\n    del _fail\n\n\nclass SessionInterface:\n    \"\"\"The basic interface you have to implement in order to replace the\n    default session interface which uses werkzeug's securecookie\n    implementation.  The only methods you have to implement are\n    :meth:`open_session` and :meth:`save_session`, the others have\n    useful defaults which you don't need to change.\n\n    The session object returned by the :meth:`open_session` method has to\n    provide a dictionary like interface plus the properties and methods","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/pallets/flask/blob/6a2f545bfd8ed31e19066a299296917e034aca58/src/flask/sessions.py#L72-L108","documentation":"When Flask's default session interface cannot open a signed cookie session because `app.secret_key` is unset, it substitutes a `NullSession` (src/flask/sessions.py:83-97). Reads return an empty session, but every mutating method (`__setitem__`, `pop`, `clear`, `update`, etc.) is bound to `_fail`, which raises this RuntimeError. It exists to give a clear message instead of silently issuing unsigned, tamperable session cookies.","triggerScenarios":"Any write to `flask.session` (e.g. `session['user_id'] = 1`, `session.pop('cart')`, `session.clear()`) while `app.secret_key`/`app.config['SECRET_KEY']` is None. Also triggered indirectly by `flask_login.login_user()`, `flash()`, or CSRF extensions that store tokens in the session.","commonSituations":"New projects that never set SECRET_KEY; setting it via an env var (`SECRET_KEY=os.environ.get('SECRET_KEY')`) that is missing in production/Docker; setting config after blueprints already captured it; app-factory setups where config loading is skipped in a worker; `flash()` calls failing in tutorials.","solutions":["Set a secret key before handling requests: `app.secret_key = '...'` or `app.config['SECRET_KEY'] = '...'` (load from an env var; generate with `python -c \"import secrets; print(secrets.token_hex(32))\"`).","Fail fast on missing configuration: raise at startup if `SECRET_KEY` is unset rather than discovering it on first session write.","Verify the env var actually reaches the process (Docker/compose env, systemd unit, CI secrets) — reference it by name, don't print the value.","If sessions are intentionally unused, remove the `session`/`flash`/login calls instead."],"exampleFix":"# before\napp = Flask(__name__)\n\n@app.route('/login', methods=['POST'])\ndef login():\n    session['user'] = request.form['user']  # RuntimeError\n\n# after\napp = Flask(__name__)\napp.secret_key = os.environ['SECRET_KEY']  # fail fast if unset","handlingStrategy":"validation","validationCode":"import os\n\napp.secret_key = os.environ[\"FLASK_SECRET_KEY\"]  # fail fast at startup\nassert app.secret_key, \"FLASK_SECRET_KEY must be set before using sessions\"","typeGuard":"def sessions_enabled(app) -> bool:\n    return bool(app.secret_key or app.config.get(\"SECRET_KEY\"))","tryCatchPattern":"try:\n    session[\"user_id\"] = user.id\nexcept RuntimeError as exc:\n    if \"secret key\" in str(exc):\n        raise RuntimeError(\"SECRET_KEY not configured; set FLASK_SECRET_KEY\") from exc\n    raise","preventionTips":["Set SECRET_KEY at app creation from an environment variable and fail startup if it is missing — don't wait for the first session write.","Never hardcode the secret key in source; load it from the environment or a secret manager and reference it by name only.","Add a startup check (or health check) that asserts `app.secret_key` is set in every deployment environment.","Use a distinct, random key per environment (`python -c \"import secrets; print(secrets.token_hex(32))\"`)."],"tags":["flask","python","session","configuration","security"],"analyzedSha":"6a2f545bfd8ed31e19066a299296917e034aca58","analyzedAt":"2026-07-31T19:13:49.921Z","schemaVersion":2}