invoke-ai/InvokeAI · warning · TimeoutError
Timeout exceeded
Error message
Timeout exceeded
What it means
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.
Source
Thrown at invokeai/app/services/download/download_default.py:312
job.status will be set to DownloadJobStatus.CANCELLED
"""
if job.status in [DownloadJobStatus.WAITING, DownloadJobStatus.RUNNING]:
job.cancel()
def cancel_all_jobs(self) -> None:
"""Cancel all jobs (those not in enqueued, running or paused state)."""
for job in self._jobs.values():
if not job.in_terminal_state:
self.cancel_job(job)
def wait_for_job(self, job: DownloadJobBase, timeout: int = 0) -> DownloadJobBase:
"""Block until the indicated job has reached terminal state, or when timeout limit reached."""
start = time.time()
while not job.in_terminal_state:
if self._job_terminated_event.wait(timeout=0.25): # in case we miss an event
self._job_terminated_event.clear()
if timeout > 0 and time.time() - start > timeout:
raise TimeoutError("Timeout exceeded")
return job
def _start_workers(self, max_workers: int) -> None:
"""Start the requested number of worker threads."""
self._stop_event.clear()
for i in range(0, max_workers): # noqa B007
worker = threading.Thread(target=self._download_next_item, daemon=True)
self._logger.debug(f"Download queue worker thread {worker.name} starting.")
worker.start()
self._worker_pool.add(worker)
def _download_next_item(self) -> None:
"""Worker thread gets next job on priority queue."""
done = False
while not done:
if self._stop_event.is_set():
done = True
continueView on GitHub (pinned to 0b6a024f2f)
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
Example fix
// before service.wait_for_job(job, timeout=30) // after service.wait_for_job(job, timeout=600) # or timeout=0
Defensive patterns
Strategy: try-catch
Validate before calling
import time
def reasonable_timeout(bytes_expected: int, bytes_per_sec: float) -> int:
return max(60, int(bytes_expected / max(bytes_per_sec, 1)) * 2) Type guard
def is_waiting_safe(job, timeout) -> bool:
return hasattr(job, "in_terminal_state") and (timeout == 0 or timeout > 0) Try / catch
try:
job = service.wait_for_job(job, timeout=estimated_timeout)
except TimeoutError:
logger.warning(f"job {job.id} still running after timeout; status={job.status}")
# poll again or cancel Prevention
- 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
When it happens
Trigger: 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).
Common situations: Large model downloads over slow connections with a short timeout, network stalls, or waiting on a cancelled/paused job that never reaches terminal state.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- DashScope task {task_id} timed out after {_TASK_POLL_TIMEOUT
- Timeout exceeded
- Unexpected error while getting current queue item: {e}
- Unexpected error while getting next queue item: {e}
- Attempt to start the download service twice
AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29).
Data as JSON: /api/errors/062d652cdae882a7.
Report an issue: GitHub.