{"record":{"id":"3b3238457bd993d9","repo":"github/copilot-sdk","slug":"timeout-after-timeout-s-waiting-for-session-idle","errorCode":null,"errorMessage":"Timeout after {timeout}s waiting for session.idle","messagePattern":"Timeout after (.+?)s waiting for session\\.idle","errorType":"exception","errorClass":"TimeoutError","httpStatus":null,"severity":"error","filePath":"python/copilot/session.py","lineNumber":1930,"sourceCode":"                logger,\n                logging.DEBUG,\n                \"CopilotSession.send_and_wait complete\",\n                total_start,\n                session_id=self.session_id,\n                completed_by=\"idle\",\n                assistant_message_received=last_assistant_message is not None,\n            )\n            return last_assistant_message\n        except TimeoutError:\n            log_timing(\n                logger,\n                logging.WARNING,\n                \"CopilotSession.send_and_wait failed\",\n                total_start,\n                session_id=self.session_id,\n                completed_by=\"timeout\",\n            )\n            raise TimeoutError(f\"Timeout after {timeout}s waiting for session.idle\")\n        finally:\n            unsubscribe()\n\n    def on(self, handler: Callable[[SessionEvent], None]) -> Callable[[], None]:\n        \"\"\"\n        Subscribe to events from this session.\n\n        Events include assistant messages, tool executions, errors, and session\n        state changes. Multiple handlers can be registered and will all receive\n        events.\n\n        Args:\n            handler: A callback function that receives session events. The function\n                takes a single :class:`SessionEvent` argument and returns None.\n\n        Returns:\n            A function that, when called, unsubscribes the handler.\n","sourceCodeStart":1912,"sourceCodeEnd":1948,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/python/copilot/session.py#L1912-L1948","documentation":"Raised by CopilotSession.send_and_wait in python/copilot/session.py when the session does not emit a session.idle event within the given timeout after a prompt is sent. asyncio.wait_for raises TimeoutError, which is caught, logged, and re-raised with a message including the timeout in seconds.","triggerScenarios":"Calling send_and_wait(prompt, timeout=N) where the agent turn takes longer than N seconds, or the session.idle event never fires (e.g. idle arrives in AUTOPILOT mode which the handler deliberately ignores, or the session errored/hung).","commonSituations":"Long-running agent tasks (big refactors, slow tools) exceeding a default or hard-coded timeout; extremely slow network to the Copilot backend; a mode where idle events are suppressed (SessionMode.AUTOPILOT); a stuck tool call that never completes.","solutions":["Increase the timeout argument passed to send_and_wait to exceed the expected turn duration.","Prefer listening for the final assistant message / session.idle via session.on() with your own timeout policy instead of a tight send_and_wait timeout.","Check for a preceding SessionError event — a hung or failed turn may never emit idle; inspect session logs.","If using AUTOPILOT mode, don't rely on idle-based waiting; consume assistant message events directly.","Retry the send if the turn is idempotent, or resume the session and continue."],"exampleFix":"// before\nmessage = await session.send_and_wait(prompt, timeout=30)  # too short for long turns\n\n// after\nmessage = await session.send_and_wait(prompt, timeout=600)  # allow long agent turns","handlingStrategy":"retry","validationCode":"expected_turn_seconds = estimate_turn_duration(prompt)\nif expected_turn_seconds >= timeout:\n    timeout = expected_turn_seconds * 2","typeGuard":"null","tryCatchPattern":"try:\n    message = await session.send_and_wait(prompt, timeout=timeout)\nexcept TimeoutError:\n    logging.warning(\"turn exceeded %ss; continuing to stream events\", timeout)\n    message = await wait_for_next_assistant_message(session, extra_timeout=timeout)","preventionTips":["Set timeouts relative to expected agent workload, not fixed small defaults.","Subscribe via session.on() so you keep receiving events even after a send_and_wait timeout.","Watch for SessionError events — a broken turn may never emit idle.","Avoid idle-based waiting in AUTOPILOT mode."],"tags":["timeout","asyncio","session","idle"],"backgroundTag":"request-timeout","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}