{"record":{"id":"efe4c0e3cb9eac87","repo":"invoke-ai/InvokeAI","slug":"timeout-exceeded-efe4c0","errorCode":null,"errorMessage":"Timeout exceeded","messagePattern":"Timeout exceeded","errorType":"exception","errorClass":"TimeoutError","httpStatus":null,"severity":"error","filePath":"invokeai/app/services/model_install/model_install_default.py","lineNumber":573,"sourceCode":"    def get_job_by_source(self, source: ModelSource) -> List[ModelInstallJob]:  # noqa D102\n        return [x for x in self._install_jobs if x.source == source]\n\n    def get_job_by_id(self, id: int) -> ModelInstallJob:  # noqa D102\n        jobs = [x for x in self._install_jobs if x.id == id]\n        if not jobs:\n            raise ValueError(f\"No job with id {id} known\")\n        assert len(jobs) == 1\n        assert isinstance(jobs[0], ModelInstallJob)\n        return jobs[0]\n\n    def wait_for_job(self, job: ModelInstallJob, timeout: int = 0) -> ModelInstallJob:\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._install_completed_event.wait(timeout=5):  # in case we miss an event\n                self._install_completed_event.clear()\n            if timeout > 0 and time.time() - start > timeout:\n                raise TimeoutError(\"Timeout exceeded\")\n        return job\n\n    def wait_for_installs(self, timeout: int = 0) -> List[ModelInstallJob]:  # noqa D102\n        \"\"\"Block until all installation jobs are done.\"\"\"\n        start = time.time()\n        restore_timeout = timeout if timeout > 0 else None\n        if not self._wait_for_restore_complete(timeout=restore_timeout):\n            raise TimeoutError(\"Timeout exceeded\")\n\n        while True:\n            # The completion callback removes a download from this cache while holding\n            # the same lock it uses to enqueue the install. Do not observe the cache\n            # between those two operations.\n            with self._lock:\n                downloads_pending = bool(self._download_cache)\n            if not downloads_pending:\n                break\n            if self._downloads_changed_event.wait(timeout=0.25):  # in case we miss an event","sourceCodeStart":555,"sourceCodeEnd":591,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/services/model_install/model_install_default.py#L555-L591","documentation":"wait_for_job() blocks polling a single ModelInstallJob until it reaches terminal state. If the job does not finish within the supplied timeout (seconds), it raises TimeoutError('Timeout exceeded'). The job itself may still be running or stuck (e.g. slow or stalled download).","triggerScenarios":"Calling wait_for_job(job, timeout=N) where the install/download takes longer than N seconds; timeout=0 means no timeout, so this only fires with a positive timeout; a stalled download queue also causes it.","commonSituations":"CI scripts with tight timeouts waiting for large model downloads; stalled network downloads exceeding the caller's timeout; caller sets a short timeout for a multi-GB model.","solutions":["Increase the timeout parameter to accommodate the model size and network speed (or pass 0 to wait indefinitely).","Instead of blocking, poll the job's status periodically and handle progress/cancel.","Check network/disk issues or the install queue if the job appears permanently stuck.","On timeout, inspect job.status/error via get_job_by_id() before retrying; resume via restart_job if failed."],"exampleFix":"// before\njob = service.wait_for_job(install_job, timeout=30)\n// after\njob = service.wait_for_job(install_job, timeout=1800)  # allow 30 min for large downloads","handlingStrategy":"try-catch","validationCode":"# estimate: ensure timeout scales with expected download size\neffective_timeout = max(timeout, estimated_bytes / bytes_per_second)","typeGuard":null,"tryCatchPattern":"try:\n    job = service.wait_for_job(install_job, timeout=1800)\nexcept TimeoutError:\n    job = service.get_job_by_id(install_job.id)  # inspect current status instead of assuming failure","preventionTips":["Set generous timeouts proportional to model size and bandwidth (or 0 for unbounded).","Prefer polling job status over long blocking waits in scripts.","Monitor network health before large downloads.","Treat timeout as 'not done yet', not 'failed' — re-check job state afterwards."],"tags":["timeout","download","concurrency"],"backgroundTag":"operation-timeout","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}