odysseus-dev/odysseus · warning · HTTPException
Session not found
Error message
Session not found
What it means
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.
Source
Thrown at routes/history/history_routes.py:256
db.close()
return {
"history": history_dict,
"model": session.model,
"endpoint_url": session.endpoint_url,
"name": session.name,
}
@router.post("/api/session/{session_id}/truncate")
async def truncate_session(request: Request, session_id: str):
_verify_session_owner(request, session_id)
try:
body = await request.json()
keep_count = body.get("keep_count", 0)
result = session_manager.truncate_messages(session_id, keep_count)
return {"status": "ok", "kept": keep_count, "truncated": result}
except KeyError:
raise HTTPException(404, "Session not found")
except Exception as e:
logger.error(f"Truncate error {session_id}: {e}")
raise HTTPException(500, str(e))
@router.post("/api/session/{session_id}/message")
async def add_message(request: Request, session_id: str):
"""Add a message to a session (for slash command persistence)."""
_verify_session_owner(request, session_id)
try:
body = await request.json()
role = body.get("role", "assistant")
content = body.get("content", "")
if not content:
raise HTTPException(400, "content is required")
metadata = body.get("metadata")
_reserve_message_uploads(request, content, metadata)
msg = ChatMessage(role=role, content=content, metadata=metadata)
session_manager.add_message(session_id, msg)View on GitHub (pinned to f9235ebbf1)
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
Defensive patterns
Strategy: fallback
Validate before calling
def can_truncate(session_id: str) -> bool:
r = requests.get(f'{base}/api/sessions', headers=hdrs, timeout=30)
return any(s.get('id') == session_id for s in r.json().get('sessions', r.json())) Try / catch
try:
truncate_session(sid, keep_count=2)
except HTTPError as e:
if e.response.status_code == 404:
pass # session gone (server restart) — nothing to truncate, converge UI
else:
raise Prevention
- 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
When it happens
Trigger: 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.
Common situations: Client resume flow after server restart; long-lived browser tab with a stale session id; splitting truncation between DB-backed and memory-backed sessions.
Related errors
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/50adf0967a5c0d75.
Report an issue: GitHub.