{"record":{"id":"1d3e2944890ca2c4","repo":"ZhuLinsen/daily_stock_analysis","slug":"request-not-active","errorCode":"request_not_active","errorMessage":"This Agent request is no longer running","messagePattern":"This Agent request is no longer running","errorType":"http","errorClass":"HTTPException","httpStatus":404,"severity":"info","filePath":"api/v1/endpoints/agent.py","lineNumber":669,"sourceCode":"\n    return StreamingResponse(\n        event_generator(),\n        media_type=\"text/event-stream\",\n        headers={\n            \"Cache-Control\": \"no-cache\",\n            \"X-Accel-Buffering\": \"no\",\n            \"Connection\": \"keep-alive\",\n        },\n    )\n\n\n@router.post(\"/chat/stream/{request_id}/cancel\")\nasync def cancel_agent_chat_stream(request_id: str):\n    \"\"\"Signal cancellation while the original Codex SSE remains open.\"\"\"\n    with _ACTIVE_CODEX_STREAMS_LOCK:\n        cancel_event = _ACTIVE_CODEX_STREAMS.get(request_id)\n    if cancel_event is None:\n        raise HTTPException(\n            status_code=404,\n            detail={\n                \"error\": \"request_not_active\",\n                \"message\": \"This Agent request is no longer running\",\n            },\n        )\n    cancel_event.set()\n    return {\"accepted\": True, \"request_id\": request_id}\n","sourceCodeStart":651,"sourceCodeEnd":678,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/api/v1/endpoints/agent.py#L651-L678","documentation":"POST /agent/chat/stream/{request_id}/cancel returns HTTP 404 code=request_not_active when no active Codex SSE stream is registered under that request_id. The lookup (api/v1/endpoints/agent.py:666-669) reads _ACTIVE_CODEX_STREAMS under lock; an entry only exists while a codex_app_server chat stream is open. Cancellation is cooperative: the endpoint sets the cancel_event which the stream's progress_callback checks.","triggerScenarios":"Cancelling after the stream already completed normally (race between UI stop button and stream end); cancelling a request_id that was never started or was mistyped; cancelling a stream on a different backend (non-codex backends never register entries); cancelling against a different server process/worker than the one holding the stream (registry is per-process, agent.py:47).","commonSituations":"Stop button in the web/desktop client firing after the SSE already closed; retrying a cancel that succeeded; deployments with multiple uvicorn workers where the cancel call lands on a worker that does not own the stream; delayed cancel after a server restart cleared the in-memory dict.","solutions":["Treat 404 from cancel as benign idempotent success — the stream is already gone, nothing to cancel","Guard the UI: only show/enable the cancel control while the SSE connection for that request_id is open","Ensure cancel requests reach the same worker as the stream (sticky routing or single worker for agent endpoints)","Log request_id correlation client-side so mismatches between started and cancelled ids are obvious"],"exampleFix":"// before\nawait fetch(`/api/v1/agent/chat/stream/${id}/cancel`, {method:'POST'}); // throws on 404\n\n// after\nconst res = await fetch(`/api/v1/agent/chat/stream/${id}/cancel`, {method:'POST'});\nif (res.status === 404) {\n  // stream already ended; nothing to cancel\n  return { alreadyStopped: true };\n}\nif (!res.ok) throw new Error('cancel failed');","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    resp = post_cancel(request_id)\nexcept HTTPError as e:\n    if e.response.status_code == 404 and 'request_not_active' in e.response.text:\n        pass  # already finished; treat as success (idempotent cancel)\n    else:\n        raise","preventionTips":["Only expose the cancel control while the SSE connection for that request_id is open","Treat cancel as idempotent by design — 404 is the 'already stopped' answer, not an error","Correlate request_id between stream start and cancel calls client-side"],"tags":["agent","http-404","cancellation","sse","idempotency"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}