{"record":{"id":"70e59d5c4f095b98","repo":"invoke-ai/InvokeAI","slug":"reason","errorCode":null,"errorMessage":"{reason}","messagePattern":"\\{reason\\}","errorType":"http","errorClass":"HTTPError","httpStatus":null,"severity":"error","filePath":"invokeai/app/services/download/download_default.py","lineNumber":491,"sourceCode":"                job.total_bytes = expected\n                job.expected_total_bytes = expected\n                job.bytes = resume_from\n                job.download_path = job.download_path or job.dest\n                self._in_progress_path(job.download_path).rename(job.download_path)\n                self._signal_job_started(job)\n                self._signal_job_complete(job)\n                return\n            job.resume_required = True\n            job.resume_message = \"Resume refused by server. Restart required.\"\n            job.pause()\n            raise DownloadJobCancelledException(\"Resume refused by server. Restart required.\")\n        if not resp.ok:\n            host = urlparse(str(resp.url or url)).netloc\n            status = resp.status_code\n            reason = resp.reason\n            if status >= 500:\n                self._logger.error(f\"Remote server error from {host}: HTTP {status} {reason}\")\n                raise HTTPError(reason)\n            self._logger.error(f\"Download failed from {host}: HTTP {status} {reason}\")\n            raise HTTPError(reason)\n\n        job.content_type = resp.headers.get(\"Content-Type\")\n        job.etag = resp.headers.get(\"ETag\") or job.etag\n        job.last_modified = resp.headers.get(\"Last-Modified\") or job.last_modified\n        content_length = int(resp.headers.get(\"content-length\", 0))\n\n        if job.dest.is_dir():\n            parsed_url = urlparse(str(url))\n            file_name = os.path.basename(parsed_url.path)  # default is to use the last bit of the URL\n\n            if match := re.search('filename=\"(.+)\"', resp.headers.get(\"Content-Disposition\", \"\")):\n                remote_name = match.group(1)\n                if self._validate_filename(job.dest.as_posix(), remote_name):\n                    file_name = remote_name\n\n            # The URL path is attacker-influenced too -- a final segment of \"..\" would","sourceCodeStart":473,"sourceCodeEnd":509,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/services/download/download_default.py#L473-L509","documentation":"After the initial header request, if the response is not OK the library logs the remote host and status and raises requests' HTTPError with the response reason phrase. This branch handles the initial (non-resume) failure; statuses >= 500 are logged as 'Remote server error'. The reason string (e.g. 'Not Found', 'Forbidden') becomes the exception message.","triggerScenarios":"The streaming GET in _do_download returns any 4xx/5xx status on the first request — 404 for a dead model URL, 403 for auth-gated repos, 429 rate limiting, or 5xx server faults.","commonSituations":"Typo'd or removed model file URL; downloading from Hugging Face gated repos without a token; corporate proxy returning 403/407; origin server overloaded (502/503) during large-model releases.","solutions":["Read the logged 'Download failed from <host>: HTTP <status>' line to get the exact status and fix the root cause (fix URL, add auth header/token).","For 5xx, retry with backoff — the failure is transient server-side.","For 403/401, supply credentials: set the appropriate Authorization header via the job's request headers or HF token configuration.","Verify the URL resolves in a browser / with `curl -I` and update the model listing or remote URL in your config."],"exampleFix":"// before: bare URL without auth for a gated repo\nqueue.submit(HttpSource(url='https://huggingface.co/gated-model/weights.safetensors'), dest)\n\n// after: pass an auth header with the job\nheaders = {'Authorization': f'Bearer {hf_token}'}\nqueue.submit(HttpSource(url='https://huggingface.co/gated-model/resolve/main/weights.safetensors', headers=headers), dest)","handlingStrategy":"try-catch","validationCode":"import requests\nr = requests.head(url, allow_redirects=True, timeout=10)\nif r.status_code >= 400:\n    raise SystemExit(f'URL unhealthy before submit: HTTP {r.status_code} {r.reason}')","typeGuard":null,"tryCatchPattern":"try:\n    queue.submit(HttpSource(url=url), dest)\nexcept HTTPError as e:\n    logger.error('download rejected: %s — check URL and auth', e)\nexcept requests.exceptions.HTTPError as e:\n    status = e.response.status_code if e.response is not None else None\n    if status and status >= 500:\n        retry_with_backoff()\n    else:\n        fix_url_or_credentials()","preventionTips":["Validate model URLs with a HEAD request before queueing.","Store auth tokens for gated repos in config/env and attach them as headers.","Monitor the app log for 'Download failed from <host>' lines to catch dead URLs early."],"tags":["network","http","download","http-client"],"backgroundTag":"http-request-failed","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}