invoke-ai/InvokeAI · info · DownloadJobCancelledException
Job was cancelled before start
Error message
Job was cancelled before start
What it means
Worker thread _download_next_item() raises DownloadJobCancelledException('Job was cancelled before start') when it dequeues a job whose `cancelled` flag is already set. The exception is handled internally to route the job to its cancellation callbacks — callers normally never see it thrown outward.
Source
Thrown at invokeai/app/services/download/download_default.py:337
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
try:
job = self._queue.get(timeout=1)
except Empty:
continue
try:
if job.cancelled:
raise DownloadJobCancelledException("Job was cancelled before start")
job.job_started = get_iso_timestamp()
self._do_download(job)
if job.status != DownloadJobStatus.COMPLETED:
self._signal_job_complete(job)
except DownloadJobCancelledException:
if job.paused:
self._signal_job_paused(job)
else:
self._signal_job_cancelled(job)
self._cleanup_cancelled_job(job)
except Exception as excp:
job.error_type = excp.__class__.__name__ + f"({str(excp)})"
job.error = traceback.format_exc()
self._signal_job_error(job, excp)
finally:
job.job_ended = get_iso_timestamp()
self._job_terminated_event.set() # signal a change to terminal state
self._download_part2parent.pop(job.id, None) # if this is a subpart of a multipart job, remove itView on GitHub (pinned to 0b6a024f2f)
Solutions
- No fix needed — this is the expected internal cancellation path; cancellation callbacks (on_cancelled) will fire
- If you see it propagate in custom worker code, ensure exceptions derive from DownloadJobCancelledException are handled like the default worker does
- Avoid calling cancel_job() concurrently with queue mutation if you don't need pre-start cancellation
Example fix
// before (custom worker)
job = queue.get()
self._do_download(job)
// after
job = queue.get()
if job.cancelled:
raise DownloadJobCancelledException("Job was cancelled before start")
self._do_download(job) Defensive patterns
Strategy: try-catch
Validate before calling
def job_is_cancellable(job) -> bool:
return not job.in_terminal_state and not job.cancelled
# only call cancel_job when job_is_cancellable(job) Type guard
def is_active_job(job) -> bool:
return not job.cancelled and not job.in_terminal_state Try / catch
try:
self._do_download(job)
except DownloadJobCancelledException:
job.status = DownloadJobStatus.CANCELLED
job.on_cancelled(job) Prevention
- Check job.cancelled before running custom worker logic
- Register on_cancelled callbacks so pre-start cancellation is observed
- Don't treat DownloadJobCancelledException as a failure — it's the normal cancel path
- Avoid double-cancelling jobs already flagged cancelled
When it happens
Trigger: cancel_job() was called (setting job.cancelled) while the job was still sitting in the queue, then a worker dequeued it and detected the flag before running the download.
Common situations: User cancels a queued download via the UI/API before a worker picks it up; burst of queued downloads cancelled en masse during shutdown.
Related errors
- Unexpected error while canceling all except current: {e}
- Job was cancelled at caller's request
- Unexpected error while enqueuing batch: {e}
- Unexpected error while listing all queue items: {e}
- Unexpected error while listing all queue item ids: {e}
AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29).
Data as JSON: /api/errors/355cf45448a5bfb4.
Report an issue: GitHub.