spacedriveapp/spacedrive · critical · anyhow::Error
Chunk {} checksum mismatch
Error message
Chunk {} checksum mismatch What it means
Each FileChunk carries a per-chunk blake3 checksum; recomputing blake3 over the received bytes mismatched (strategy.rs:653-660), so chunk data was corrupted, duplicated, or reordered in flight or in memory. With QUIC's integrity protection, genuine wire corruption is unlikely — suspect a producer bug, memory issue, or build mismatch. Unlike the byte-count and final-checksum failures, this branch returns WITHOUT deleting the partial destination file, so a corrupt partial file remains on disk.
Source
Thrown at core/src/ops/files/copy/strategy.rs:656
let msg_len = u32::from_be_bytes(len_buf) as usize;
let mut msg_buf = vec![0u8; msg_len];
recv_stream.read_exact(&mut msg_buf).await?;
let msg: crate::service::network::protocol::file_transfer::FileTransferMessage =
rmp_serde::from_slice(&msg_buf)?;
match msg {
crate::service::network::protocol::file_transfer::FileTransferMessage::FileChunk {
chunk_index,
data,
chunk_checksum,
..
} => {
// Verify chunk checksum
let calculated = blake3::hash(&data);
if calculated.as_bytes() != &chunk_checksum {
return Err(anyhow::anyhow!(
"Chunk {} checksum mismatch",
chunk_index
));
}
// Write chunk
file.write_all(&data).await?;
if let Some(h) = &mut hasher {
h.update(&data);
}
total_bytes_received += data.len() as u64;
// Progress callback
if let Some(cb) = progress_callback {
cb(total_bytes_received, file_size);
}
if chunk_index % 100 == 0 {View on GitHub (pinned to 6dfeccf211)
Solutions
- Delete any leftover partial file at the destination, then retry the transfer
- Verify both devices run identical core versions so chunk framing matches
- If it reproduces at the same chunk index, capture sender-side logs and report a protocol bug
- If corruption recurs across unrelated transfers, run a memory diagnostic on both machines
Example fix
// before (strategy.rs, current behavior leaves the partial file)
if calculated.as_bytes() != &chunk_checksum {
return Err(anyhow::anyhow!("Chunk {} checksum mismatch", chunk_index));
}
// after: clean up the corrupt partial file like the other integrity failures
if calculated.as_bytes() != &chunk_checksum {
let _ = fs::remove_file(&final_dest_path).await;
return Err(anyhow::anyhow!("Chunk {} checksum mismatch", chunk_index));
} Defensive patterns
Strategy: retry
Try / catch
match remote_strategy.execute_pull(ctx, &src, &dst).await {
Ok(n) => Ok(n),
Err(e) if e.to_string().starts_with("Chunk") && e.to_string().ends_with("checksum mismatch") => {
// NOTE: strategy does NOT delete the partial file here — remove it before retrying
let _ = tokio::fs::remove_file(&expected_dest).await;
remote_strategy.execute_pull(ctx, &src, &dst).await
}
Err(e) => Err(e),
} Prevention
- Delete the partial destination file before retrying — this branch leaves it behind
- Pin both devices to the same core version so chunk framing matches
- Escalate to a bug report if the same chunk index fails repeatedly
When it happens
Trigger: Sender/receiver running mismatched versions that frame chunks differently; buffer corruption under memory pressure; duplicated chunk delivery after a stream event; producer-side serialization bug on the remote.
Common situations: Mixed daemon versions during rolling upgrades; hardware memory errors; reproducible failure at the same chunk index indicating a protocol bug.
Related errors
- Final checksum mismatch
- Failed to calculate checksum: {}
- Pull request rejected: {}
- Unexpected response to pull request
- Byte count mismatch: expected {}, got {}
AI-assisted analysis of spacedriveapp/spacedrive@6dfeccf211 (2026-08-16).
Data as JSON: /api/errors/8add3d4fcbb516c9.
Report an issue: GitHub.