{"record":{"id":"09c58fd13c9f7d24","repo":"odysseus-dev/odysseus","slug":"session-not-found-09c58f","errorCode":null,"errorMessage":"Session not found","messagePattern":"Session not found","errorType":"http","errorClass":"HTTPException","httpStatus":404,"severity":"error","filePath":"routes/webhook/webhook_routes.py","lineNumber":262,"sourceCode":"        token_owner = getattr(request.state, \"api_token_owner\", None)\n\n        from core.models import ChatMessage\n        from src.llm_core import llm_call_async\n        from src.endpoint_resolver import build_chat_url, build_headers, build_models_url, normalize_base\n\n        message = body.message.strip()\n        if not message:\n            raise HTTPException(400, \"Message is required\")\n\n        session_id = body.session\n        sess = None\n\n        # --- Case 1: Resume an existing session ---\n        if session_id and session_manager:\n            try:\n                sess = session_manager.get_session(session_id)\n            except (KeyError, Exception):\n                raise HTTPException(404, \"Session not found\")\n            # SECURITY: verify the API-token's user owns this session — without\n            # this any token holder could resume any user's chat by passing its\n            # ID. The token's user is on request.state.user (set by API-token\n            # middleware); fall back to require_user if not present.\n            try:\n                from src.auth_helpers import get_current_user as _gcu\n                _tok_user = token_owner or getattr(request.state, \"user\", None) or _gcu(request)\n            except Exception:\n                _tok_user = None\n            # Strict ownership (see _caller_owns_session): fail closed so a\n            # null-owner / cross-owner session can't be resumed by an arbitrary\n            # chat-scoped token.\n            _sess_owner = getattr(sess, \"owner\", None)\n            if not _caller_owns_session(_sess_owner, _tok_user):\n                raise HTTPException(404, \"Session not found\")\n\n        # --- Case 2: Direct API key + model (no pre-configured endpoint needed) ---\n        if not sess and body.api_key:","sourceCodeStart":244,"sourceCodeEnd":280,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/routes/webhook/webhook_routes.py#L244-L280","documentation":"HTTP 404 from POST /v1/chat when resuming a session: session_manager.get_session(session_id) raised (KeyError or any Exception). The broad except (KeyError, Exception) intentionally converts every lookup failure — unknown id, expired/purged session, corrupted session store — into the same 404 so it does not leak internals.","triggerScenarios":"Passing a session id that never existed, was deleted, or was lost when the process restarted and sessions were not persisted/loaded; a session id from a different deployment.","commonSituations":"Automation retrying an old conversation after server restart without saved sessions; long-lived n8n workflows storing session ids past their retention; typo'd/truncated UUID.","solutions":["Start a fresh conversation by omitting body.session, capture the new session id from the response, and store that","Verify the session exists (GET session endpoint / admin UI) before reusing it","Ensure session persistence is enabled so ids survive restarts"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"if resp.status_code == 404 and 'Session not found' in detail:\n    resp = chat(message=body.message, api_key=..., model=...)  # fresh session, no `session` field\n    store_new_session_id(resp[\"session\"])","preventionTips":["Store the session id returned by each chat call and use only the latest","Expect sessions to disappear after restarts; design automation to restart conversations gracefully"],"tags":["session","not-found","chat","http-404"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}