{"record":{"id":"743f61c5802c77a6","repo":"zed-industries/zed","slug":"session-not-found","errorCode":null,"errorMessage":"Session not found","messagePattern":"Session not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/agent/src/agent.rs","lineNumber":2147,"sourceCode":"        self.0\n            .update(cx, |this, cx| this.load_thread(id, project, cx))\n    }\n\n    fn run_turn(\n        &self,\n        session_id: acp::SessionId,\n        cx: &mut App,\n        f: impl 'static\n        + FnOnce(Entity<Thread>, &mut App) -> Result<mpsc::UnboundedReceiver<Result<ThreadEvent>>>,\n    ) -> Task<Result<acp::PromptResponse>> {\n        let Some((thread, acp_thread)) = self.0.update(cx, |agent, _cx| {\n            agent\n                .sessions\n                .get_mut(&session_id)\n                .map(|s| (s.thread.clone(), s.acp_thread.clone()))\n        }) else {\n            log::error!(\"Session not found in run_turn: {}\", session_id);\n            return Task::ready(Err(anyhow!(\"Session not found\")));\n        };\n        log::debug!(\"Found session for: {}\", session_id);\n\n        let response_stream = match f(thread, cx) {\n            Ok(stream) => stream,\n            Err(err) => return Task::ready(Err(err)),\n        };\n        Self::handle_thread_events(\n            response_stream,\n            acp_thread.downgrade(),\n            Some(self.clone()),\n            cx,\n        )\n    }\n\n    fn handle_thread_events(\n        mut events: mpsc::UnboundedReceiver<Result<ThreadEvent>>,\n        acp_thread: WeakEntity<AcpThread>,","sourceCodeStart":2129,"sourceCodeEnd":2165,"githubUrl":"https://github.com/zed-industries/zed/blob/bc538def4545534201bbfcac4e95ac34ea6501b6/crates/agent/src/agent.rs#L2129-L2165","documentation":"run_turn looks session_id up in agent.sessions to obtain the Thread and AcpThread entities; a miss logs 'Session not found in run_turn' and returns a ready Err task — the per-turn closure f that would start generation is never invoked.","triggerScenarios":"Sending a chat turn for a session id not present in the in-memory sessions map: never created in this agent, removed after ending, or stale after an agent restart.","commonSituations":"Client reconnect after agent restart while reusing pre-restart ids; session ended concurrently with a queued turn; turn dispatched during session teardown.","solutions":["Only enqueue turns after session creation has resolved","On this error, recreate the session and resend the turn","Serialize session teardown with pending turn dispatch so turns cannot race removal"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Only enqueue turns for sessions the agent actually holds\nif !agent.has_session(&session_id) {\n    let session = agent.create_session(project, cx).await?;\n    session_id = session.id;\n}\nagent.run_turn(session_id, cx, move |thread, cx| thread.send(prompt, cx))","typeGuard":null,"tryCatchPattern":"match run_turn(...).await {\n    Err(error) if error.to_string() == \"Session not found\" => {\n        // Recreate the session and replay the turn once.\n        let session = agent.create_session(project, cx).await?;\n        agent.run_turn(session.id, cx, replay_closure).await\n    }\n    other => other,\n}","preventionTips":["Enqueue turns only after session creation resolves","Drop queued turns when a session is torn down instead of letting them race","On reconnect, rebuild the session map before resuming the conversation"],"tags":["rust","zed","agent","session","acp"],"backgroundTag":null,"analyzedSha":"bc538def4545534201bbfcac4e95ac34ea6501b6","analyzedAt":"2026-08-16T07:30:46.435Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}