invoke-ai/InvokeAI · info · DownloadJobCancelledException

Job was cancelled at caller's request

Error message

Job was cancelled at caller's request

What it means

Inside the streaming download loop, each chunk first checks job.cancelled. If the caller requested cancellation (via the queue's cancel API), the loop aborts immediately by raising DownloadJobCancelledException('Job was cancelled at caller's request'). The partial `.downloading` file is left in place so a later resume can continue from the last chunk. This is expected control flow, not a malfunction.

Source

Thrown at invokeai/app/services/download/download_default.py:608

        elif resp.status_code != 200:
            host = urlparse(str(resp.url or url)).netloc
            status = resp.status_code
            reason = resp.reason
            if status >= 500:
                self._logger.error(f"Remote server error from {host}: HTTP {status} {reason}")
                raise HTTPError(reason)
            self._logger.error(f"Download failed from {host}: HTTP {status} {reason}")
            raise HTTPError(reason)

        self._logger.debug(f"{job.source}: Downloading {job.download_path}")
        report_delta = job.total_bytes / 100  # report every 1% change
        last_report_bytes = 0

        # DOWNLOAD LOOP
        with open(in_progress_path, open_mode) as file:
            for data in resp.iter_content(chunk_size=DOWNLOAD_CHUNK_SIZE):
                if job.cancelled:
                    raise DownloadJobCancelledException("Job was cancelled at caller's request")

                job.bytes += file.write(data)
                if (job.bytes - last_report_bytes >= report_delta) or (job.bytes >= job.total_bytes):
                    last_report_bytes = job.bytes
                    self._signal_job_progress(job)

        if job.total_bytes > 0 and job.bytes < job.total_bytes:
            job.resume_required = True
            job.resume_message = "Download interrupted. Resume required."
            job.pause()
            raise DownloadJobCancelledException("Download interrupted. Resume required.")

        # if we get here we are done and can rename the file to the original dest
        self._logger.debug(f"{job.source}: saved to {job.download_path} (bytes={job.bytes})")
        in_progress_path.rename(job.download_path)

    def _validate_url(self, url: str) -> None:
        """Refuse to fetch URLs that point at addresses only the server can reach."""

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. No fix needed: handle DownloadJobCancelledException as a normal cancellation; the partial `.downloading` file supports later resume.
  2. If the cancellation was unintentional, resume the job — it continues from job.bytes without redownloading everything.
  3. During shutdown, wait for jobs or call the queue's graceful-stop API instead of hard-cancel to finish small downloads.
  4. Clean up orphaned `.downloading` files only if you never intend to resume.

Example fix

// before: treating cancellation as fatal
try:
    queue.join()
except Exception as e:
    logger.critical(e)

// after: distinguish cancellation
try:
    queue.join()
except DownloadJobCancelledException:
    logger.info('download cancelled; resumable later')
Defensive patterns

Strategy: try-catch

Validate before calling

# check before cancelling whether the job is nearly done
if job.total_bytes and (job.bytes / job.total_bytes) > 0.98:
    queue.join(job.id)  # let it finish instead of cancelling
else:
    queue.cancel(job.id)

Try / catch

try:
    queue.join()
except DownloadJobCancelledException as e:
    if "caller's request" in str(e):
        logger.info('job cancelled by user; partial .downloading kept for resume')
    else:
        logger.warning('job paused for other reason: %s', e)

Prevention

When it happens

Trigger: Calling RemoteDownloadService.cancel(job_id) — or cancelling the source/queue — while bytes are actively streaming in _do_download's iter_content loop.

Common situations: User cancels a slow large-model download from the UI; app shutdown drains the queue and cancels in-flight jobs; a script aborts a download after a timeout; duplicate job cancelled in favor of another.

Related errors


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