{"record":{"id":"1be6d406197ed0db","repo":"docling-project/docling","slug":"timed-out-waiting-for-task-task-id-after-wait-t","errorCode":null,"errorMessage":"Timed out waiting for task {task_id} after {wait_timeout:.2f}s.","messagePattern":"Timed out waiting for task (.+?) after (.+?)s\\.","errorType":"exception","errorClass":"TaskTimeoutError","httpStatus":null,"severity":"warning","filePath":"docling/service_client/watchers.py","lineNumber":114,"sourceCode":"        poll_client_interval: float | None,\n        default_timeout: float,\n    ) -> None:\n        self._poll_status = poll_status\n        self._poll_server_wait = poll_server_wait\n        self._poll_client_interval = (\n            poll_server_wait if poll_client_interval is None else poll_client_interval\n        )\n        self._default_timeout = default_timeout\n\n    def iter_updates(\n        self, task_id: str, timeout: float | None = None\n    ) -> Iterator[TaskStatusResponse]:\n        wait_timeout = self._default_timeout if timeout is None else timeout\n        deadline = time.monotonic() + wait_timeout\n        while True:\n            remaining = deadline - time.monotonic()\n            if remaining <= 0:\n                raise TaskTimeoutError(\n                    f\"Timed out waiting for task {task_id} after {wait_timeout:.2f}s.\"\n                )\n\n            poll_wait = min(self._poll_server_wait, remaining)\n            poll_started = time.monotonic()\n            update = self._poll_status(task_id, poll_wait)\n            yield update\n            if is_terminal_task_status(update):\n                return\n\n            # Keep a minimum client-side poll cadence when server-side wait is ignored.\n            sleep_for = _poll_sleep_duration(\n                poll_started=poll_started,\n                poll_interval=self._poll_client_interval,\n                deadline=deadline,\n            )\n            if sleep_for > 0:\n                time.sleep(sleep_for)","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/docling-project/docling/blob/61d76f1ff3f8428065465889f7b4577da7df704c/docling/service_client/watchers.py#L96-L132","documentation":"TaskTimeoutError raised by PollingWatcher.iter_updates when the monotonic deadline (default_timeout or the per-call timeout) expires before the task reaches a terminal status. Each poll passes the remaining window to the server's long-poll; once remaining <= 0 the wait fails.","triggerScenarios":"wait_for_terminal()/iter_updates() on a task that runs longer than the configured timeout — big documents, queued behind many jobs, or a stuck task that never transitions.","commonSituations":"Default timeout too small for large batch conversions; overloaded single-worker service; task actually failed to progress (worker crash) and never terminates.","solutions":["Pass a larger timeout to wait_for_terminal (or raise the client's default) sized to real conversion time","Check service queue depth/worker count — the task may simply be waiting in queue","Note the task keeps running server-side: you may re-attach with iter_updates(task_id) instead of resubmitting"],"exampleFix":"# before\nstatus = watcher.wait_for_terminal(task_id)  # default timeout too short\n\n# after\nstatus = watcher.wait_for_terminal(task_id, timeout=1800.0)","handlingStrategy":"retry","validationCode":null,"typeGuard":"def is_task_timeout(exc: BaseException) -> bool:\n    return isinstance(exc, TaskTimeoutError)","tryCatchPattern":"from docling.service_client.exceptions import TaskTimeoutError\n\ntry:\n    status = watcher.wait_for_terminal(task_id, timeout=timeout_s)\nexcept TaskTimeoutError:\n    status = watcher.wait_for_terminal(task_id, timeout=timeout_s)  # re-attach; task still runs","preventionTips":["Size timeouts to p99 conversion time plus queue wait, not median","Remember timeout expires client-side only — re-attach rather than resubmit"],"tags":["timeout","polling","watchers","task-lifecycle"],"backgroundTag":null,"analyzedSha":"61d76f1ff3f8428065465889f7b4577da7df704c","analyzedAt":"2026-08-14T23:53:18.727Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}