{"record":{"id":"f8ebe0b4b6ab8295","repo":"tonhowtf/omniget","slug":"size-mismatch-expected-bytes-got-http-fetcher","errorCode":null,"errorMessage":"size mismatch: expected {} bytes, got {}","messagePattern":"size mismatch: expected (.+?) bytes, got (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/http_fetcher.rs","lineNumber":571,"sourceCode":"        if let Some(p) = resume_pump {\n            p.abort();\n        }\n        let _ = progress_pump.await;\n\n        if let Some(e) = first_err {\n            return Err(e);\n        }\n\n        let segs = segments.lock().await;\n        let all_done = segs\n            .iter()\n            .all(|s| s.state.load(Ordering::Relaxed) == SEG_DONE);\n        if !all_done {\n            return Err(anyhow!(\"not all segments completed\"));\n        }\n        let actual = tokio::fs::metadata(part_path).await?.len();\n        if actual != total {\n            return Err(anyhow!(\n                \"size mismatch: expected {} bytes, got {}\",\n                total,\n                actual\n            ));\n        }\n\n        Ok(())\n    }\n}\n\nstruct ProbeResult {\n    content_length: Option<u64>,\n    accept_ranges: bool,\n}\n\n/// O que dá para saber de um recurso remoto antes de baixar.\n#[derive(Debug, Clone)]\npub struct RemoteProbe {","sourceCodeStart":553,"sourceCodeEnd":589,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/http_fetcher.rs#L553-L589","documentation":"After every segment reports done, the library compares the assembled .part file's size on disk (tokio::fs::metadata) against the expected total byte count derived from Content-Length. A mismatch means bytes were lost, duplicated, or never written despite all segments claiming success. It is the final integrity gate before renaming the part into place.","triggerScenarios":"actual != total after join: a worker wrote fewer bytes than its range (truncated body/stream ended early), two workers wrote overlapping or gapped ranges, or the server sent a 206 whose Content-Range covered a different span than requested.","commonSituations":"Flaky proxies/middleboxes truncating responses, servers misreporting Content-Length, disk-full conditions that silently shorten writes, or off-by-one errors in exclusive/inclusive range end handling.","solutions":["Delete the .part file and re-run the download; transient truncation often clears on retry.","Verify each worker writes exactly (end - start + 1) bytes and seeks to the correct offset before writing.","Validate the server's Content-Range in the 206 response matches the requested bytes range before writing (see the guard added around line 969).","Check available disk space and that writes use write_all, not write, so partial writes are not silently accepted."],"exampleFix":"// before\nfile.write(&buf).await?; // may write fewer bytes\n// after\nfile.write_all(&buf).await?;","handlingStrategy":"validation","validationCode":"// pre-check disk headroom and expected size before starting\nlet meta = std::fs::metadata(dest_dir)?;\nlet free = fs2::free_space(dest_dir)?;\nif free <= expected_total { return Err(\"insufficient disk space\"); }","typeGuard":null,"tryCatchPattern":"match download(...).await {\n    Err(e) if e.to_string().contains(\"size mismatch\") => {\n        // discard .part, re-download; if it repeats, suspect server/proxy truncation\n    }\n    other => { other?; }\n}","preventionTips":["Use write_all (never write) for segment body writes so partial writes error out.","Validate the 206 Content-Range header against the requested range before writing.","Monitor disk space on the destination volume before large downloads.","Prefer servers that send accurate Content-Length; distrust ones that vary between HEAD and GET."],"tags":["download","integrity","size-mismatch","rust"],"backgroundTag":"checksum-mismatch","analyzedSha":"8600b91f4246848bac346874daa9e61c1fc5677a","analyzedAt":"2026-09-12T14:29:19.317Z","contentChangedAt":"2026-09-12T14:29:19.317Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}