pallets/flask · error · RuntimeError
The session is unavailable because no secret key was set. S
Error message
The session is unavailable because no secret key was set. Set the secret_key on the application to something unique and secret.
What it means
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.
Source
Thrown at src/flask/sessions.py:90
def __init__(
self,
initial: c.Mapping[str, t.Any] | None = None,
) -> None:
def on_update(self: te.Self) -> None:
self.modified = True
super().__init__(initial, on_update)
class NullSession(SecureCookieSession):
"""Class used to generate nicer error messages if sessions are not
available. Will still allow read-only access to the empty session
but fail on setting.
"""
def _fail(self, *args: t.Any, **kwargs: t.Any) -> t.NoReturn:
raise RuntimeError(
"The session is unavailable because no secret "
"key was set. Set the secret_key on the "
"application to something unique and secret."
)
__setitem__ = __delitem__ = clear = pop = popitem = update = setdefault = _fail
del _fail
class SessionInterface:
"""The basic interface you have to implement in order to replace the
default session interface which uses werkzeug's securecookie
implementation. The only methods you have to implement are
:meth:`open_session` and :meth:`save_session`, the others have
useful defaults which you don't need to change.
The session object returned by the :meth:`open_session` method has to
provide a dictionary like interface plus the properties and methodsView on GitHub ↗ (pinned to 6a2f545bfd)
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.
Example fix
# before
app = Flask(__name__)
@app.route('/login', methods=['POST'])
def login():
session['user'] = request.form['user'] # RuntimeError
# after
app = Flask(__name__)
app.secret_key = os.environ['SECRET_KEY'] # fail fast if unset Defensive patterns
Strategy: validation
Validate before calling
import os app.secret_key = os.environ["FLASK_SECRET_KEY"] # fail fast at startup assert app.secret_key, "FLASK_SECRET_KEY must be set before using sessions"
Type guard
def sessions_enabled(app) -> bool:
return bool(app.secret_key or app.config.get("SECRET_KEY")) Try / catch
try:
session["user_id"] = user.id
except RuntimeError as exc:
if "secret key" in str(exc):
raise RuntimeError("SECRET_KEY not configured; set FLASK_SECRET_KEY") from exc
raise Prevention
- 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))"`).
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- The environment variable {variable_name!r} is not set and as
- If an instance path is provided it must be absolute. A relat
- Tag '{key}' is already registered.
- Working outside of application context. Attempted to use fu
- Working outside of request context. Attempted to use functi
AI-assisted analysis of pallets/flask@6a2f545bfd (2026-07-31).
Data as JSON: /data/errors/bc586ed409dd403c.json.
Report an issue: GitHub ↗.