{"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/c89b7bf38974ad317177389f5bfe28236f0d64e3/src-tauri/src/managers/model/download.rs#L256-L292","documentation":"Raised on a 206 Partial Content reply whose Content-Range start offset does not exactly equal the end of the local partial file. Appending such a body would silently corrupt the model (bytes skipped or duplicated), so the partial is deleted and the error returned. This is a server-misbehavior guard: a correct server must echo the exact 'bytes=N-' offset that was requested.","triggerScenarios":"Server responds 206 but with a Content-Range starting at 0 (ignoring the Range while claiming partial), a missing/unparseable Content-Range header on a 206, or a proxy rewriting range responses.","commonSituations":"Misconfigured CDNs or object stores that ack Range but return full bodies; middleboxes/proxies that reconstitute responses and drop Content-Range; exotic servers that clamp ranges differently.","solutions":["Retry — the tainted partial was deleted and the next attempt starts over cleanly.","If reproducible for one host, that host is broken for range downloads — switch to the primary/mirror URL.","Bypass corporate proxies known to mangle range requests.","Report the URL if the official catalog entry consistently triggers it."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"match manager.download_model(model_id, None).await {\n    Ok(_) => Ok(()),\n    Err(e) if e.to_string().contains(\"Content-Range starting at\") => {\n        // tainted partial already deleted; clean restart is the only safe move\n        manager.download_model(model_id, None).await\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Always validate the 206 Content-Range offset equals the partial length before appending (this code does — keep it).","Avoid proxies that reconstitute range responses when downloading large models.","When a host repeatedly mis-answers ranges, stop resuming against it and switch sources."],"tags":["download","content-range","http-206","resume","server-misbehavior"],"backgroundTag":"content-range-mismatch","analyzedSha":"c89b7bf38974ad317177389f5bfe28236f0d64e3","analyzedAt":"2026-08-17T10:29:55.597Z","contentChangedAt":"2026-08-17T10:29:55.597Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}