odysseus-dev/odysseus · error · HTTPException

Session '{session}' not found

Error message

Session '{session}' not found

What it means

The non-streaming chat endpoint could not find the given session ID in the session manager after ownership verification passed. get_session raises KeyError for unknown IDs, which the handler maps to a 404. Ownership is checked first, so a foreign session also surfaces as this 404 rather than a 403.

Source

Thrown at routes/chat_routes.py:697

    async def chat_endpoint(request: Request, chat_request: ChatRequest) -> Dict[str, Any]:
        _set_user_time_from_request(request)

        message = chat_request.message
        session = chat_request.session
        att_ids = chat_request.attachments or []
        use_web = chat_request.use_web
        use_research = chat_request.use_research
        time_filter = chat_request.time_filter
        preset_id = chat_request.preset_id

        # Verify the caller owns this session before loading it.
        # Without this, any authenticated user can post into another user's chat.
        _verify_session_owner(request, session)

        try:
            sess = session_manager.get_session(session)
        except KeyError:
            raise HTTPException(404, f"Session '{session}' not found")
        owner = effective_user(request)
        if _clear_orphaned_session_endpoint(sess, owner=owner):
            raise HTTPException(400, "Selected model endpoint was removed. Pick another model in Settings.")

        # Empty model + live endpoint = setup race (Issue #587). Repair from
        # the endpoint's cached model list before privilege checks, which
        # otherwise see "" and behave inconsistently with the allowlist.
        _recover_empty_session_model(sess, session, owner=owner)
        if not getattr(sess, "model", "").strip():
            raise HTTPException(
                400,
                "No model selected for this chat. Open the model picker and choose one before sending.",
            )
        if not (getattr(sess, "endpoint_url", "") or "").strip():
            raise HTTPException(400, "Selected model endpoint is not configured")

        # Same allowed_models + daily-cap gate as chat_stream (mirror so the
        # non-streaming path can't be used to bypass).

View on GitHub (pinned to f9235ebbf1)

Solutions

  1. List sessions via the sessions API and use a current, owned session ID
  2. Create a new session when the client gets this 404 instead of retrying the same ID
  3. If sessions should survive restarts, verify session persistence/save is functioning

Example fix

// before
fetch(`/api/chat/${sessionId}`, {method:'POST', body})
// after
const r = await fetch(`/api/chat/${sessionId}`, {method:'POST', body});
if (r.status === 404) { sessionId = await createNewSession(); /* retry once */ }
Defensive patterns

Strategy: fallback

Validate before calling

const sessions = await fetch('/api/sessions').then(r=>r.json());
const ok = sessions.some(s => s.id === sessionId);
if (!ok) sessionId = await createSession();

Try / catch

try { await postChat(sessionId, body); }
catch (e) { if (e.status === 404 && /not found/.test(e.message)) { sessionId = await createSession(); await postChat(sessionId, body); } else throw e; }

Prevention

When it happens

Trigger: POST to the non-streaming chat route with a session ID that was deleted, never existed, or belongs to another user (cross-user IDs are masked as 404).

Common situations: Client kept a stale session ID after server restart cleared in-memory sessions (if not persisted); session deleted from another tab or by the sessions UI; hand-crafted session_id values.

Related errors


AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14). Data as JSON: /api/errors/feb2512f78708d27. Report an issue: GitHub.