langchain-ai/langgraph · error · TimeoutError
Sync run.start gate timeout.
Error message
Sync run.start gate timeout.
What it means
Timeout in the sync stream controller: after sending run.start, the controller blocks on a gate until the server acknowledges the run (first lifecycle/task event). If no acknowledgment arrives within run_start_timeout seconds, this error fires, usually indicating the server is slow, unreachable, or the run failed to start.
Solutions
- Increase the run_start_timeout value passed when opening the stream
- Verify server connectivity and that the assistant/graph exists so the run can actually start
- Retry the operation; transient network or server load can cause the first acknowledgment to be missed
Defensive patterns
Strategy: retry
When it happens
Trigger: Thrown at libs/sdk-py/langgraph_sdk/stream/sync_controller.py:123 when the library encounters an invalid state.
Common situations: See trigger scenarios.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
AI-assisted analysis of langchain-ai/langgraph@38031739e5 (2026-08-26).
Data as JSON: /api/errors/2d87cd9c27274192.
Report an issue: GitHub.
Appendix: source
Thrown at libs/sdk-py/langgraph_sdk/stream/sync_controller.py:123
def signal_paused(self) -> None:
"""Wake every active subscription iterator on interrupt (run pause).
Pushes the terminal sentinel (`None`) into every subscription queue.
Iterators see `None` and return; the shared SSE keeps running so
re-iteration after `run.respond(...)` registers a fresh subscription
and resumes.
"""
with self._lock:
subs = list(self._subscriptions.values())
for sub in subs:
sub.queue.put(None)
def reconcile_stream(self, candidate_filter: SubscribeParams) -> None:
if self._run_start_gate is not None and not self._run_start_gate.wait(
timeout=self._run_start_timeout
):
raise TimeoutError("Sync run.start gate timeout.")
with self._lock:
if (
self._shared_stream is not None
and self._shared_stream_filter is not None
and filter_covers(self._shared_stream_filter, dict(candidate_filter))
):
return
new_filter = self._compute_current_union(extra=candidate_filter)
old_stream = self._shared_stream
self._shared_stream = self._transport.open_event_stream(
self._filter_with_since(new_filter)
)
self._shared_stream_filter = new_filter
if old_stream is not None:
drain_thread = threading.Thread(
target=self._drain_and_close,
args=(old_stream,),
daemon=True,View on GitHub (pinned to 38031739e5)