{"record":{"id":"1bf11274e91962ba","repo":"jdx/mise","slug":"server-returned-an-invalid-content-range-response","errorCode":null,"errorMessage":"server returned an invalid Content-Range response","messagePattern":"server returned an invalid Content-Range response","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/http.rs","lineNumber":1024,"sourceCode":"                if resp.status() == StatusCode::PARTIAL_CONTENT {\n                    let Some((state, _)) = resume else {\n                        partial.clear()?;\n                        if !restarted_without_resume {\n                            restarted_without_resume = true;\n                            continue;\n                        }\n                        bail!(\"server returned partial content without a resumable request\");\n                    };\n                    let content_range = resp\n                        .headers()\n                        .get(CONTENT_RANGE)\n                        .and_then(|value| value.to_str().ok())\n                        .and_then(parse_content_range);\n                    let Some(ParsedContentRange::Bytes { start, end, total }) = content_range\n                    else {\n                        partial.clear()?;\n                        if restarted_without_resume {\n                            bail!(\"server returned an invalid Content-Range response\");\n                        }\n                        restarted_without_resume = true;\n                        continue;\n                    };\n                    let validator = response_validator(resp.headers());\n                    let response_length_matches = resp\n                        .content_length()\n                        .is_none_or(|length| length == end - start + 1);\n                    if start != offset\n                        || end + 1 != total\n                        || !response_length_matches\n                        || state.total_size.is_some_and(|expected| expected != total)\n                        || validator\n                            .as_ref()\n                            .is_some_and(|value| !value.matches(&state.validator))\n                    {\n                        partial.clear()?;\n                        if restarted_without_resume {","sourceCodeStart":1006,"sourceCodeEnd":1042,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/http.rs#L1006-L1042","documentation":"During a resumed download, mise sent a Range request and the server answered 206 Partial Content, but the Content-Range header could not be parsed as a byte range (missing, malformed, or an 'unsatisfied'/'other' form). mise restarts the download once without resume; if the retry also fails to yield a parseable byte Content-Range, it gives up with this error. It protects against writing partial bytes at the wrong offset.","triggerScenarios":"Calling mise's HTTP download path (src/http.rs resume_download) against a server that responds 206 with a missing or unparseable Content-Range header, both on the initial resumed request and after the automatic restart-without-resume retry also returns a 206 whose Content-Range cannot be parsed.","commonSituations":"Downloading from a proxy, CDN, or misbehaving origin that emits 206 responses with non-standard or stripped Content-Range headers; middleboxes that mangle headers; caching proxies that return 206 from a stale entry.","solutions":["Clear the partial download file/state (delete the .part file) and retry the download from scratch.","Retry later or from a different network to bypass the misbehaving proxy/CDN.","If you control the server/proxy, fix it to emit a valid 'Content-Range: bytes start-end/total' header on 206 responses."],"exampleFix":"// before: download via corporate proxy that mangles Content-Range\nexport HTTPS_PROXY=http://proxy.corp:8080; mise install node@22\n// after: bypass the proxy for tool downloads\nexport NO_PROXY=github.com,objects.githubusercontent.com; mise install node@22","handlingStrategy":"retry","validationCode":"let range = headers.get(\"content-range\").and_then(|v| v.to_str().ok());\nlet ok = matches!(range, Some(r) if r.starts_with(\"bytes \") && r.contains('/'));\nif !ok { /* restart download from scratch, removing the .part file */ }","typeGuard":null,"tryCatchPattern":"match download().await {\n    Err(e) if e.to_string().contains(\"invalid Content-Range\") => {\n        remove_partial_download();\n        download().await?; // fresh, non-resumed attempt\n    }\n    other => other?,\n}","preventionTips":["Avoid resuming through proxies/CDNs known to mangle Content-Range headers.","Clear stale .part files before retrying downloads through unusual networks.","Test download servers with `curl -r 0-1 -D -` to confirm valid 206 + Content-Range."],"tags":["network","download","http","content-range"],"backgroundTag":"unexpected-http-status","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}