{"record":{"id":"88cecbb212f6cdb8","repo":"cjpais/Handy","slug":"server-returned-content-range-starting-at-ex","errorCode":null,"errorMessage":"server returned Content-Range starting at {:?}, expected {}","messagePattern":"server returned Content-Range starting at (.+?), expected (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src-tauri/src/managers/model/download.rs","lineNumber":274,"sourceCode":"            resume_from = 0;\n        }\n        if !response.status().is_success() {\n            return Err(anyhow::anyhow!(\n                \"server returned HTTP {}\",\n                response.status()\n            ));\n        }\n        // On a 206, trust but verify the offset: a reply starting anywhere but\n        // exactly our partial's end would silently corrupt the file on append.\n        if resume_from > 0 && response.status() == reqwest::StatusCode::PARTIAL_CONTENT {\n            let starts_at = response\n                .headers()\n                .get(reqwest::header::CONTENT_RANGE)\n                .and_then(|v| v.to_str().ok())\n                .and_then(content_range_start);\n            if starts_at != Some(resume_from) {\n                let _ = fs::remove_file(partial_path);\n                return Err(anyhow::anyhow!(\n                    \"server returned Content-Range starting at {:?}, expected {}\",\n                    starts_at,\n                    resume_from\n                ));\n            }\n        }\n        // When the catalog pins the size, a server advertising a different\n        // total is already misbehaving — reject before writing anything.\n        if let (Some(expected), Some(len)) = (expected_size, response.content_length()) {\n            if resume_from + len != expected {\n                return Err(anyhow::anyhow!(\n                    \"server advertises {} bytes, expected {}\",\n                    resume_from + len,\n                    expected\n                ));\n            }\n        }\n","sourceCodeStart":256,"sourceCodeEnd":292,"githubUrl":"https://github.com/cjpais/Handy/blob/98a4d80cce8ad41efec2a419b59d9e81229a35d7/src-tauri/src/managers/model/download.rs#L256-L292","documentation":"On HTTP 206 the downloader parses the Content-Range header and requires the start offset to equal resume_from exactly (the partial's byte length). A reply starting anywhere else — including a missing or unparseable Content-Range, where starts_at is None — would silently corrupt the file on append, so the partial is deleted and the error returned.","triggerScenarios":"Server replies 206 but restarts from byte 0; Content-Range header missing or malformed so content_range_start returns None; object changed between the original download and the resume so offsets no longer align.","commonSituations":"Cheap mirrors or CDNs with broken Range semantics; hand-rolled static servers that label every response 206; proxies that rewrite range responses.","solutions":["Retry — the partial was removed, so the next attempt downloads from byte 0","If it persists, test the host: curl -r <offset>- <url> -D - and inspect the Content-Range header","Switch to a Range-correct source such as the official HuggingFace endpoint"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"match downloader.download_http_resumable(...).await {\n    Ok(outcome) => Ok(outcome),\n    Err(e) if e.to_string().contains(\"Content-Range starting at\") => {\n        // partial deleted by the guard; retry downloads from byte 0\n        downloader.download_http_resumable(...).await\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Validate Range support of a mirror once with curl -r before relying on resume","Treat a 206 without an exact Content-Range as a broken server, never append","Prefer endpoints with correct HTTP/1.1 Range semantics (HF, major CDNs)"],"tags":["http-206","content-range","resume","download"],"backgroundTag":"content-range-mismatch","analyzedSha":"98a4d80cce8ad41efec2a419b59d9e81229a35d7","analyzedAt":"2026-08-16T20:58:09.966Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}