odysseus-dev/odysseus · error · KeyError

Session {session_id} not found

Error message

Session {session_id} not found

What it means

KeyError from _load_session_from_db when no DbSession row with the given id exists. It is the hydrate-on-demand path: the loader queries by id, and a miss means the session was never created or was deleted, so it cannot be cached or returned.

Source

Thrown at core/session_manager.py:490

            session.message_count = (
                db.query(DbChatMessage)
                .filter(DbChatMessage.session_id == session_id)
                .count()
            )
            return True
        except Exception as e:
            logger.error(f"Error syncing session metadata {session_id}: {e}")
            return False
        finally:
            db.close()

    def _load_session_from_db(self, session_id: str):
        """Hydrate a single session (with messages) from the database."""
        db = SessionLocal()
        try:
            db_session = db.query(DbSession).filter(DbSession.id == session_id).first()
            if db_session is None:
                raise KeyError(f"Session {session_id} not found")

            session = self._db_to_session(db_session, db)
            if session:
                self.sessions[session_id] = session
            else:
                # No messages — fall back to metadata-only entry so callers
                # don't crash on KeyError for empty sessions.
                meta = self._db_to_session_meta(db_session)
                if meta is None:
                    raise KeyError(f"Session {session_id} could not be loaded")
                self.sessions[session_id] = meta

        except KeyError:
            raise
        except Exception as e:
            logger.error(f"Error loading session {session_id}: {e}")
            raise
        finally:

View on GitHub (pinned to f9235ebbf1)

Solutions

  1. Handle KeyError by listing sessions (get_sessions_for_user) and reselecting a valid id
  2. Create a new session instead of reusing the stale id
  3. If the session should exist, check the DbSession table for the row and any delete/retention job that removed it

Example fix

# before
session = sm.get_session(session_id)  # KeyError if deleted
# after
try:
    session = sm.get_session(session_id)
except KeyError:
    session = sm.create_session(...)
    session_id = session.id
Defensive patterns

Strategy: try-catch

Validate before calling

existing = db.query(DbSession.id).filter(DbSession.id == session_id).first()
if existing is None:
    raise ClientVisibleError('Session was deleted')

Try / catch

try:
    session = sm.get_session(session_id)
except KeyError:
    session = sm.create_session(owner=owner)
    session_id = session.id

Prevention

When it happens

Trigger: Calling get_session/load for an id not present in the sessions table — e.g. after the session was deleted on another device/request, a client retrying with a stale id, or a typo/garbled id.

Common situations: Client holds a session id across a delete; race between delete and a concurrent read; restoring from backup where message rows exist but the session row is gone.

Related errors


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