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
                continue

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Increase the timeout parameter to exceed realistic download duration for the file size/bandwidth
  2. Pass timeout=0 (or omit) to wait indefinitely, then handle job errors via callbacks
  3. Inspect job.status after catching the timeout to see why it stalled; cancel and retry if stuck
  4. 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

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

Related errors


AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29). Data as JSON: /api/errors/062d652cdae882a7. Report an issue: GitHub.