docling-project/docling · error · TaskTimeoutError
Timed out waiting for task {task_id} after {timeout:.2f}s.
Error message
Timed out waiting for task {task_id} after {timeout:.2f}s. What it means
TaskTimeoutError raised inside the sync WebSocketWatcher's _iter_ws_connection loop when the monotonic deadline passes before a terminal task status arrives. The deadline is set from the watcher's default timeout or the per-call timeout, and it is checked before every websocket.recv(). It means the WebSocket stayed healthy but the task did not reach a success/failure status in time.
Source
Thrown at docling/service_client/watchers.py:237
raise
except Exception as exc:
raise ServiceUnavailableError(
"WebSocket status stream is unavailable.", detail=str(exc)
) from exc
def _iter_ws_connection(
self, ws_url: str, task_id: str, deadline: float, timeout: float
) -> Iterator[TaskStatusResponse]:
with connect(
ws_url,
open_timeout=self._connect_timeout,
close_timeout=self._connect_timeout,
additional_headers=self._additional_headers,
) as websocket:
while True:
remaining = deadline - time.monotonic()
if remaining <= 0:
raise TaskTimeoutError(
f"Timed out waiting for task {task_id} after {timeout:.2f}s."
)
raw_message = websocket.recv(timeout=remaining)
envelope = WebsocketMessage.model_validate_json(raw_message)
status = _process_ws_envelope(envelope, task_id)
if status is None:
continue
yield status
if is_terminal_task_status(status):
return
# Only send "next" for UPDATE messages. The server sends
# CONNECTION once before the update loop begins; sending
# "next" in response to it would queue an extra token that
# the server later consumes as a request for a post-terminalView on GitHub (pinned to 61d76f1ff3)
Solutions
- Pass a larger timeout to the wait call (e.g. wait_for_terminal(task_id, timeout=3600))
- Raise the watcher's default timeout when constructing the service client
- Check the task status on the server (GET /v1/status/poll/{task_id}) to see whether it eventually finished, then retrieve the result instead of resubmitting
- Reduce task size (fewer pages per request) so it completes within the budget
Example fix
# before status = watcher.wait_for_terminal(task_id) # default timeout # after status = watcher.wait_for_terminal(task_id, timeout=1800.0)
Defensive patterns
Strategy: retry
Validate before calling
# Estimate needed timeout from document size before waiting estimated = max(default_timeout, num_pages * seconds_per_page) status = watcher.wait_for_terminal(task_id, timeout=estimated)
Try / catch
from docling.service_client.exceptions import TaskTimeoutError
try:
status = watcher.wait_for_terminal(task_id, timeout=1800)
except TaskTimeoutError:
# Task may still finish server-side; check once without resubmitting
status = poll_status_fn(task_id, 0.0)
if not is_terminal_task_status(status):
raise Prevention
- Size timeouts to the workload (pages x per-page cost), not the default
- For batch jobs, set default_timeout high at client construction
- Poll by task_id after a timeout instead of resubmitting the conversion
- Monitor server queue depth — growing backlog means longer waits
When it happens
Trigger: Calling wait_for_terminal()/iter_updates() on a WebSocketWatcher where the docling-serve task runs longer than the configured timeout (default_timeout or the timeout= argument), so remaining = deadline - time.monotonic() drops to <= 0 before is_terminal_task_status(status) is true.
Common situations: Large batch conversions or GPU-starved servers exceeding a default timeout; timeout left at library default for big workloads; server queue backlog; slow OCR models on CPU.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Timed out waiting for task {task_id} after {timeout:.2f}s.
- gRPC infer call failed for model {self.model_name}: {exc}
- submit_batch() requires either 'target' or 'targets'.
- submit_batch() received both 'target' and 'targets'; supply
- Service transport request failed.
AI-assisted analysis of docling-project/docling@61d76f1ff3 (2026-08-14).
Data as JSON: /api/errors/0393d7d0936d098d.
Report an issue: GitHub.