makeplane/plane · error · SessionInterrupted
The request's session was deleted before the request complet
Error message
The request's session was deleted before the request completed. The user may have logged out in a concurrent request, for example.
What it means
SessionInterrupted (Django built-in, re-raised at session.py:76) is raised when request.session.save() throws UpdateError — meaning the session record was deleted from the store between the start of the request and the response phase. The supplied message explains the canonical cause: the user logged out (or the session expired/was purged) in a concurrent request.
Source
Thrown at apps/api/plane/authentication/middleware/session.py:76
if request.session.get_expire_at_browser_close():
max_age = None
expires = None
else:
# Use different max_age based on whether it's an admin cookie
if is_admin_path:
max_age = settings.ADMIN_SESSION_COOKIE_AGE
else:
max_age = request.session.get_expiry_age()
expires_time = time.time() + max_age
expires = http_date(expires_time)
# Save the session data and refresh the client cookie.
if response.status_code < 500:
try:
request.session.save()
except UpdateError:
raise SessionInterrupted(
"The request's session was deleted before the "
"request completed. The user may have logged "
"out in a concurrent request, for example."
)
response.set_cookie(
cookie_name,
request.session.session_key,
max_age=max_age,
expires=expires,
domain=settings.SESSION_COOKIE_DOMAIN,
path=settings.SESSION_COOKIE_PATH,
secure=settings.SESSION_COOKIE_SECURE or None,
httponly=settings.SESSION_COOKIE_HTTPONLY or None,
samesite=settings.SESSION_COOKIE_SAMESITE,
)
return response
View on GitHub (pinned to 1c8a60f858)
Solutions
- Treat as transient: the client should re-authenticate (the session no longer exists).
- If frequent, check the session store (Redis) health, memory, and eviction policy — keys should not disappear mid-request.
- Avoid issuing parallel mutating requests alongside a logout; sequence logout last.
- Confirm SESSION_ENGINE points to a durable, low-latency backend.
Example fix
// before: concurrent logout + API call -> SessionInterrupted 500 // after: client waits for logout to resolve before further calls, // and re-authenticates on 500/session loss
Defensive patterns
Strategy: try-catch
Try / catch
from django.contrib.sessions.exceptions import SessionInterrupted
try:
response = middleware_get_response(request)
except SessionInterrupted:
# session vanished mid-request (concurrent logout / eviction)
response = build_reauth_required_response() Prevention
- Sequence logout last on the client; do not fire concurrent mutating requests alongside it.
- Monitor the session backend (Redis) for eviction/memory pressure.
- Use a durable SESSION_ENGINE with adequate maxmemory.
When it happens
Trigger: process_response saves the session only when status_code < 500 and the session is modified/non-empty. If the underlying session key was already removed (logout in another tab, cache eviction, Redis flush), SessionStore.save() raises UpdateError and the middleware converts it to SessionInterrupted (HTTP 500).
Common situations: User clicks logout in one tab while another long-running request is in flight; aggressive Redis eviction/memory pressure dropping session keys; multiple concurrent requests where one deletes the session; session backend misconfigured to a flaky store.
Related errors
AI-assisted analysis of makeplane/plane@1c8a60f858 (2026-08-12).
Data as JSON: /api/errors/3951922ebbb3b62b.
Report an issue: GitHub.