{"record":{"id":"50adf0967a5c0d75","repo":"odysseus-dev/odysseus","slug":"session-not-found-50adf0","errorCode":null,"errorMessage":"Session not found","messagePattern":"Session not found","errorType":"http","errorClass":"HTTPException","httpStatus":404,"severity":"warning","filePath":"routes/history/history_routes.py","lineNumber":256,"sourceCode":"                db.close()\n\n        return {\n            \"history\": history_dict,\n            \"model\": session.model,\n            \"endpoint_url\": session.endpoint_url,\n            \"name\": session.name,\n        }\n\n    @router.post(\"/api/session/{session_id}/truncate\")\n    async def truncate_session(request: Request, session_id: str):\n        _verify_session_owner(request, session_id)\n        try:\n            body = await request.json()\n            keep_count = body.get(\"keep_count\", 0)\n            result = session_manager.truncate_messages(session_id, keep_count)\n            return {\"status\": \"ok\", \"kept\": keep_count, \"truncated\": result}\n        except KeyError:\n            raise HTTPException(404, \"Session not found\")\n        except Exception as e:\n            logger.error(f\"Truncate error {session_id}: {e}\")\n            raise HTTPException(500, str(e))\n\n    @router.post(\"/api/session/{session_id}/message\")\n    async def add_message(request: Request, session_id: str):\n        \"\"\"Add a message to a session (for slash command persistence).\"\"\"\n        _verify_session_owner(request, session_id)\n        try:\n            body = await request.json()\n            role = body.get(\"role\", \"assistant\")\n            content = body.get(\"content\", \"\")\n            if not content:\n                raise HTTPException(400, \"content is required\")\n            metadata = body.get(\"metadata\")\n            _reserve_message_uploads(request, content, metadata)\n            msg = ChatMessage(role=role, content=content, metadata=metadata)\n            session_manager.add_message(session_id, msg)","sourceCodeStart":238,"sourceCodeEnd":274,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/routes/history/history_routes.py#L238-L274","documentation":"HTTP 404 from POST /api/session/{session_id}/truncate: session_manager.truncate_messages raised KeyError because the session id is not registered in the in-memory session manager. The route had already passed _verify_session_owner, so this is purely 'session absent from session_manager', most commonly after a server restart or for a DB-only session.","triggerScenarios":"POST {\"keep_count\": 2} to /api/session/{id}/truncate for an unknown/restarted-away session; truncating a session that exists in the DB but was never loaded into memory.","commonSituations":"Client resume flow after server restart; long-lived browser tab with a stale session id; splitting truncation between DB-backed and memory-backed sessions.","solutions":["Refresh the session list and confirm the id is live before truncating","Reopen/load the session so session_manager registers it, then truncate","Handle 404 by silently dropping the stale tab's truncation request"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"def can_truncate(session_id: str) -> bool:\n    r = requests.get(f'{base}/api/sessions', headers=hdrs, timeout=30)\n    return any(s.get('id') == session_id for s in r.json().get('sessions', r.json()))","typeGuard":null,"tryCatchPattern":"try:\n    truncate_session(sid, keep_count=2)\nexcept HTTPError as e:\n    if e.response.status_code == 404:\n        pass  # session gone (server restart) — nothing to truncate, converge UI\n    else:\n        raise","preventionTips":["Reopen the session (any read/create that loads it into session_manager) before truncating","Treat truncate-404 after restarts as a no-op in the UI","Avoid issuing truncates for sessions never created in this process"],"tags":["http-404","session","truncate","in-memory-state","keyerror"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}