{"record":{"id":"550066c6e7544f30","repo":"ducaale/xh","slug":"can-t-parse-content-range-header-can-t-resume-download","errorCode":null,"errorMessage":"Can't parse Content-Range header, can't resume download","messagePattern":"Can't parse Content-Range header, can't resume download","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/download.rs","lineNumber":119,"sourceCode":"        if let Some(file) = try_open_new(&candidate)? {\n            return Ok((candidate, file));\n        }\n    }\n    panic!(\"Could not create file after unreasonable number of attempts\");\n}\n\n// https://github.com/httpie/httpie/blob/84c7327057/httpie/downloads.py#L44\n// https://tools.ietf.org/html/rfc7233#section-4.2\nfn total_for_content_range(header: &str, expected_start: u64) -> Result<u64> {\n    let re_range = Regex::new(concat!(\n        r\"^bytes (?P<first_byte_pos>\\d+)-(?P<last_byte_pos>\\d+)\",\n        r\"/(?:\\*|(?P<complete_length>\\d+))$\"\n    ))\n    .unwrap();\n    let caps = re_range\n        .captures(header)\n        // Could happen if header uses unit other than bytes\n        .ok_or_else(|| anyhow!(\"Can't parse Content-Range header, can't resume download\"))?;\n    let first_byte_pos: u64 = caps\n        .name(\"first_byte_pos\")\n        .unwrap()\n        .as_str()\n        .parse()\n        .context(\"Can't parse Content-Range first_byte_pos\")?;\n    let last_byte_pos: u64 = caps\n        .name(\"last_byte_pos\")\n        .unwrap()\n        .as_str()\n        .parse()\n        .context(\"Can't parse Content-Range last_byte_pos\")?;\n    let complete_length: Option<u64> = caps\n        .name(\"complete_length\")\n        .map(|num| {\n            num.as_str()\n                .parse()\n                .context(\"Can't parse Content-Range complete_length\")","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/ducaale/xh/blob/2404aceecc08b0b2d100fedc96f57745cd5904dc/src/download.rs#L101-L137","documentation":"When resuming a download, the tool parses the server's Content-Range header with a regex expecting 'bytes <start>-<end>/<len|*>'. If the header doesn't match at all — wrong unit like 'items', missing 'bytes' prefix, malformed syntax — it aborts the resume because the byte offset can't be trusted.","triggerScenarios":"Server returns a non-bytes Content-Range unit, an unparsable or absent range portion (e.g. 'bytes */1234' is handled, but 'items 0-9/10' or 'bytes' alone is not), or a truncated/garbled header from a broken proxy.","commonSituations":"Resuming against CDNs or caches that rewrite headers, misconfigured reverse proxies stripping or mangling Content-Range, non-HTTP-standard servers on embedded devices.","solutions":["Retry the resume; if it still fails, delete the partial file and restart the download from scratch","Check the actual Content-Range header with -v/curl and confirm the unit is 'bytes' with valid syntax","Bypass or fix intermediate proxies/CDNs that mangle range headers"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"fn parseable_content_range(header: &str) -> bool {\n    header.starts_with(\"bytes \") && header.contains('-') && header.contains('/')\n}","typeGuard":null,"tryCatchPattern":"match total_for_content_range(header, expected_start) {\n    Ok(total) => resume_from(expected_start, total),\n    Err(e) if e.to_string().contains(\"Can't parse Content-Range\") => {\n        eprintln!(\"Resume aborted: {e}; restarting download\");\n        restart_download();\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Inspect the server's raw Content-Range before enabling resume","Avoid resuming through proxies/CDNs known to rewrite headers","Fall back to a fresh download when the header is unparsable"],"tags":["http","download","resume","content-range","rust"],"backgroundTag":"unexpected-response-shape","analyzedSha":"2404aceecc08b0b2d100fedc96f57745cd5904dc","analyzedAt":"2026-09-13T19:13:33.814Z","contentChangedAt":"2026-09-13T19:13:33.814Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}