Hmbown/CodeWhale · critical
Fleet artifact checksum does not match the recorded receipt
Error message
Fleet artifact checksum does not match the recorded receipt
What it means
read_verified hashes the streamed bytes and requires the result to equal the sha256 checksum recorded in the FleetArtifactRef receipt ('sha256:<hex>'). A mismatch means the file content differs from what was published, so the artifact is not valid evidence and verification fails closed.
Solutions
- Treat the artifact as compromised: do not use it as evidence; re-publish the correct content via artifacts::write to get a fresh receipt.
- Restore the original file from a backup or the producing run's output.
- Verify the FleetArtifactRef actually belongs to this path/run — a copied or stale receipt will not match different content.
- Check storage health (disk, sync layer) if corruption recurs across artifacts.
Defensive patterns
Strategy: validation
Validate before calling
// trust nothing: verify receipt checksum before using artifact evidence let (preview, size) = read_verified(ws, &artifact, preview_limit)?; // fails closed on mismatch assert_eq!(artifact.size_bytes, Some(size));
Try / catch
match read_verified(ws, &artifact, preview_limit) {
Err(e) if e.to_string().contains("checksum does not match") => {
eprintln!("artifact {} is not valid evidence; re-publish from source", artifact.path.display());
}
other => other?,
} Prevention
- Always verify via read_verified before consuming artifact content as evidence.
- Never edit published artifacts; republish under a new receipt instead.
- Keep receipts and artifacts from the same run together; don't reuse refs across runs.
- Investigate storage health if checksum failures recur.
When it happens
Trigger: The bytes streamed from the artifact hash to a digest different from artifact.checksum — content was modified, corrupted, or the receipt belongs to a different file/version despite matching size.
Common situations: Bit rot or filesystem corruption; manual editing of a published artifact; a receipt copied from another run/path; a writer that bypassed artifacts::write and wrote different content at the same size.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- Fleet artifact exceeds the 16 MiB verification limit
- Fleet artifact grew while being read
- Fleet artifact size changed
- Fleet artifact size changed while being read
- An existing Fleet artifact contains different bytes
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/02dfb2522522d721.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/fleet/artifacts.rs:88
// The digest and returned preview consume exactly the same bytes from the
// same opened file. A changed/replaced pathname is never reopened for data.
let mut reader = (&file).take(size + 1);
loop {
let count = reader.read(&mut buffer)?;
if count == 0 {
break;
}
total += count as u64;
ensure!(total <= size, "Fleet artifact grew while being read");
hasher.update(&buffer[..count]);
let remaining = preview_limit.saturating_sub(preview.len() as u64) as usize;
preview.extend_from_slice(&buffer[..count.min(remaining)]);
}
ensure!(
total == size && file.metadata()?.len() == size,
"Fleet artifact size changed while being read"
);
ensure!(
format!("sha256:{}", crate::hashing::hex_bytes(hasher.finalize())) == checksum,
"Fleet artifact checksum does not match the recorded receipt"
);
Ok((preview, size))
}
#[cfg(test)]
mod tests {
use super::*;
use codewhale_protocol::fleet::FleetArtifactKind;
fn reference(path: &str, bytes: &[u8]) -> FleetArtifactRef {
FleetArtifactRef {
kind: FleetArtifactKind::Receipt,
path: path.into(),
checksum: Some(format!("sha256:{}", crate::hashing::sha256_hex(bytes))),
mime_type: None,
size_bytes: Some(bytes.len() as u64),View on GitHub (pinned to 73e0f67d83)