{"record":{"id":"062d652cdae882a7","repo":"invoke-ai/InvokeAI","slug":"timeout-exceeded","errorCode":null,"errorMessage":"Timeout exceeded","messagePattern":"Timeout exceeded","errorType":"exception","errorClass":"TimeoutError","httpStatus":null,"severity":"warning","filePath":"invokeai/app/services/download/download_default.py","lineNumber":312,"sourceCode":"        job.status will be set to DownloadJobStatus.CANCELLED\n        \"\"\"\n        if job.status in [DownloadJobStatus.WAITING, DownloadJobStatus.RUNNING]:\n            job.cancel()\n\n    def cancel_all_jobs(self) -> None:\n        \"\"\"Cancel all jobs (those not in enqueued, running or paused state).\"\"\"\n        for job in self._jobs.values():\n            if not job.in_terminal_state:\n                self.cancel_job(job)\n\n    def wait_for_job(self, job: DownloadJobBase, timeout: int = 0) -> DownloadJobBase:\n        \"\"\"Block until the indicated job has reached terminal state, or when timeout limit reached.\"\"\"\n        start = time.time()\n        while not job.in_terminal_state:\n            if self._job_terminated_event.wait(timeout=0.25):  # in case we miss an event\n                self._job_terminated_event.clear()\n            if timeout > 0 and time.time() - start > timeout:\n                raise TimeoutError(\"Timeout exceeded\")\n        return job\n\n    def _start_workers(self, max_workers: int) -> None:\n        \"\"\"Start the requested number of worker threads.\"\"\"\n        self._stop_event.clear()\n        for i in range(0, max_workers):  # noqa B007\n            worker = threading.Thread(target=self._download_next_item, daemon=True)\n            self._logger.debug(f\"Download queue worker thread {worker.name} starting.\")\n            worker.start()\n            self._worker_pool.add(worker)\n\n    def _download_next_item(self) -> None:\n        \"\"\"Worker thread gets next job on priority queue.\"\"\"\n        done = False\n        while not done:\n            if self._stop_event.is_set():\n                done = True\n                continue","sourceCodeStart":294,"sourceCodeEnd":330,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/services/download/download_default.py#L294-L330","documentation":"wait_for_job() polls the job's terminal state every 0.25s and raises TimeoutError('Timeout exceeded') when the optional `timeout` (seconds) elapses before the job finishes. It is a client-side watchdog, not a job failure.","triggerScenarios":"Calling wait_for_job(job, timeout=N) where the download takes longer than N seconds or the job is stuck (paused, errored but not terminal, slow network).","commonSituations":"Large model downloads over slow connections with a short timeout, network stalls, or waiting on a cancelled/paused job that never reaches terminal state.","solutions":["Increase the timeout parameter to exceed realistic download duration for the file size/bandwidth","Pass timeout=0 (or omit) to wait indefinitely, then handle job errors via callbacks","Inspect job.status after catching the timeout to see why it stalled; cancel and retry if stuck","Use on_complete/on_error callbacks instead of blocking wait for long downloads"],"exampleFix":"// before\nservice.wait_for_job(job, timeout=30)\n// after\n\nservice.wait_for_job(job, timeout=600)  # or timeout=0","handlingStrategy":"try-catch","validationCode":"import time\ndef reasonable_timeout(bytes_expected: int, bytes_per_sec: float) -> int:\n    return max(60, int(bytes_expected / max(bytes_per_sec, 1)) * 2)","typeGuard":"def is_waiting_safe(job, timeout) -> bool:\n    return hasattr(job, \"in_terminal_state\") and (timeout == 0 or timeout > 0)","tryCatchPattern":"try:\n    job = service.wait_for_job(job, timeout=estimated_timeout)\nexcept TimeoutError:\n    logger.warning(f\"job {job.id} still running after timeout; status={job.status}\")\n    # poll again or cancel","preventionTips":["Size the timeout from file size and bandwidth, with headroom","Prefer on_complete/on_error callbacks over blocking waits for large files","Check job.status after a timeout to distinguish slow vs stuck","Use timeout=0 for unbounded waits in scripts with their own watchdog"],"tags":["timeout","download","polling"],"backgroundTag":"wait-timeout-exceeded","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}