invoke-ai/InvokeAI · warning · DownloadJobCancelledException
Resume refused by server. Restart required.
Error message
Resume refused by server. Restart required.
What it means
During a resume attempt, the server responded 416 (Range Not Satisfiable) but the local partial file's byte offset did not exactly equal the remote file's total size, so the library cannot trust the partial data. The job is marked resume_required and paused, and DownloadJobCancelledException is raised to force the download to restart from scratch rather than produce a corrupt file. It is a control-flow signal to the download queue, not a fatal failure of the file itself.
Source
Thrown at invokeai/app/services/download/download_default.py:484
# Range not satisfiable - local partial is already complete
match = re.fullmatch(r"bytes \*/(\d+)", resp.headers.get("Content-Range", ""), flags=re.IGNORECASE)
# Content-Range is optional on 416 responses. Reuse the size known when
# the download started, but never resume_from itself: that would accept
# every partial file as complete.
expected = int(match.group(1)) if match else (job.expected_total_bytes or job.total_bytes or None)
if expected is not None and resume_from == expected:
job.total_bytes = expected
job.expected_total_bytes = expected
job.bytes = resume_from
job.download_path = job.download_path or job.dest
self._in_progress_path(job.download_path).rename(job.download_path)
self._signal_job_started(job)
self._signal_job_complete(job)
return
job.resume_required = True
job.resume_message = "Resume refused by server. Restart required."
job.pause()
raise DownloadJobCancelledException("Resume refused by server. Restart required.")
if not resp.ok:
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)
job.content_type = resp.headers.get("Content-Type")
job.etag = resp.headers.get("ETag") or job.etag
job.last_modified = resp.headers.get("Last-Modified") or job.last_modified
content_length = int(resp.headers.get("content-length", 0))
if job.dest.is_dir():
parsed_url = urlparse(str(url))
file_name = os.path.basename(parsed_url.path) # default is to use the last bit of the URLView on GitHub (pinned to 0b6a024f2f)
Solutions
- Delete the stale partial file (the `.downloading` file in the destination directory) and resubmit the download so it restarts from byte 0.
- Verify the remote URL still points at the same file version (check ETag/Last-Modified or file size); pin a specific revision if the host is a model registry.
- Check any proxy/CDN in front of the host that may answer 416 with a mismatched Content-Range; bypass it or disable resume.
- Catch DownloadJobCancelledException and inspect job.resume_message to distinguish this from a caller cancellation, then restart the job programmatically.
Example fix
// before: blindly retrying the job, which keeps failing with 416
queue.resume(job.id)
// after: discard the partial file, then restart cleanly
from pathlib import Path
partial = Path(job.local_path).with_suffix('.downloading')
if partial.exists():
partial.unlink()
queue.cancel(job.id)
queue.submit(job.source, job.dest) Defensive patterns
Strategy: retry
Validate before calling
import requests
head = requests.head(url, allow_redirects=True)
remote_size = int(head.headers.get('Content-Length', 0))
partial = dest_path.with_suffix('.downloading')
if partial.exists() and remote_size and partial.stat().st_size > remote_size:
partial.unlink() # stale/inconsistent partial, remove before resuming Try / catch
try:
queue.resume(job.id)
except DownloadJobCancelledException as e:
if 'Restart required' in str(e):
partial = Path(job.local_path).with_suffix('.downloading')
partial.unlink(missing_ok=True)
queue.cancel(job.id)
queue.submit(job.source, job.dest) Prevention
- Pin remote file versions (revision/commit hash on HuggingFace) so files don't change between attempts.
- Periodically clean stale `.downloading` files whose size no longer matches remote Content-Length.
- Download from mirrors known to answer Range requests consistently.
When it happens
Trigger: A previously interrupted download is resumed (_do_download with resume_from > 0) and the server returns HTTP 416 while the Content-Range total (or job.expected_total_bytes/job.total_bytes) does not match resume_from — e.g. the remote file changed size or was replaced between sessions.
Common situations: Mirror/HuggingFace file was updated after the first download attempt; a proxy or CDN returns 416 with inconsistent Content-Range; the local .downloading file was truncated or corrupted externally while the server thinks the range is unsatisfiable.
Related errors
- {reason}
- Download interrupted. Resume required.
- DashScope request failed with status {response.status_code}
- DashScope async request failed with status {response.status_
- DashScope task poll failed with status {response.status_code
AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29).
Data as JSON: /api/errors/9fd99327947efac0.
Report an issue: GitHub.