datawhalechina/hello-agents · warning · HTTPException

会话不存在或已过期

Error message

会话不存在或已过期

What it means

FastAPI HTTPException 404 raised by get_session_pair when a session_id is not a key in the in-memory active_sessions dict. Sessions live only in process memory — there is no persistence and no TTL, so 'expired' really means 'gone': server restart, session never created, or id typo. Multi-worker deployments (uvicorn --workers N) make this frequent because session created on worker A is invisible to worker B.

Source

Thrown at Co-creation-projects/afei-GuessWhoAmI/backend/main.py:90

)

# Configure CORS
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Global session storage: session_id -> (GameSession, HistoricalFigureAgent)
active_sessions: Dict[str, tuple] = {}

# Helper functions
def get_session_pair(session_id: str):
    """Get game session and agent, raise exception if not found"""
    if session_id not in active_sessions:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="会话不存在或已过期"
        )
    return active_sessions[session_id]

def create_response(success: bool, message: str, data: dict = None, error: str = None) -> GameResponse:
    """Create standardized response"""
    return GameResponse(
        success=success,
        message=message,
        data=data,
        error=error
    )

# API endpoints
@app.get("/")
async def root():
    """Root endpoint"""

View on GitHub (pinned to 606a07d341)

Solutions

  1. Client should treat 404 on this endpoint as 'session lost' and transparently call /api/game/start to create a new session
  2. If running multiple workers, pin sessions with sticky routing or move session state to Redis
  3. Disable auto-reload in any long-game deployment (uvicorn --reload off)
  4. Verify the session_id matches the exact UUID returned by /api/game/start (no truncation, no encoding issues)

Example fix

# before (client pseudocode)
resp = post('/api/game/ask', {'session_id': sid, ...})
if resp.status_code != 200: raise

# after
resp = post('/api/game/ask', {'session_id': sid, ...})
if resp.status_code == 404 and '会话不存在' in resp.json()['detail']:
    # session lost (restart / other worker) — restart the game
    start = post('/api/game/start').json()
    sid = start['data']['session_id']
    resp = post('/api/game/ask', {'session_id': sid, ...})
Defensive patterns

Strategy: fallback

Validate before calling

# client-side: confirm session still valid before a long interaction
async def ensure_session(sid: str | None) -> str:
    if sid and (await client.get(f'/api/game/state/{sid}')).status_code == 200:
        return sid
    start = (await client.post('/api/game/start')).json()
    return start['data']['session_id']

Try / catch

from fastapi import HTTPException

try:
    session, agent = get_session_pair(session_id)
except HTTPException as e:
    if e.status_code == 404:
        # transparent restart for the player
        return create_response(False, "会话已失效,请重新开始", error="SESSION_LOST")
    raise

Prevention

When it happens

Trigger: Client calls /api/game/ask or similar with a session_id from before a server restart; typo'd or truncated UUID; calling an endpoint before POST /api/game/start; load balancer routing the second request to a different worker; long-running game where the process restarted on deploy.

Common situations: Dev server auto-reloading on file change (kills all sessions); Docker container redeploy; scaling to multiple replicas behind a load balancer; frontend keeping a stale session_id in localStorage across days.

Related errors


AI-assisted analysis of datawhalechina/hello-agents@606a07d341 (2026-08-14). Data as JSON: /api/errors/9b18ee39d4757a0d. Report an issue: GitHub.