spacedriveapp/spacedrive · error · std::io::Error

Checksum verification failed: source={}, dest={}

Error message

Checksum verification failed: source={}, dest={}

What it means

After a copy with verify_checksum enabled, the code finalizes two blake3 hashers (one fed from the source stream, one from the destination stream) and compares digests. A mismatch means the bytes written differ from the bytes read; the destination file is deleted and ErrorKind::InvalidData is returned with both hex digests for post-mortem correlation.

Source

Thrown at core/src/ops/files/copy/strategy.rs:962

	dest_file.flush().await?;
	dest_file.sync_all().await?;

	if let Some(callback) = progress_callback {
		callback(file_size, u64::MAX);
		ctx.log(format!(
			"Strategy final progress: {} / {} bytes (100%)",
			total_copied, file_size
		));
	}

	if verify_checksum {
		if let (Some(source_hasher), Some(dest_hasher)) = (source_hasher, dest_hasher) {
			let source_hash = source_hasher.finalize();
			let dest_hash = dest_hasher.finalize();

			if source_hash != dest_hash {
				let _ = fs::remove_file(destination).await;
				return Err(std::io::Error::new(
					std::io::ErrorKind::InvalidData,
					format!(
						"Checksum verification failed: source={}, dest={}",
						source_hash.to_hex(),
						dest_hash.to_hex()
					),
				));
			}

			ctx.log(format!(
				"Checksum verification passed for {}: {}",
				destination.display(),
				source_hash.to_hex()
			));
		}
	}

	let source_metadata = fs::metadata(source).await?;

View on GitHub (pinned to 6dfeccf211)

Solutions

  1. Retry the copy once: transient media and network glitches are the most common cause and the code already removed the bad destination
  2. If it fails repeatedly on the same file, hash the source twice and compare: a changing digest means the source is being modified during the read, not the copy is broken
  3. Check destination disk health (smartctl) and cabling, or copy to a different volume to isolate the failing side
  4. Pause other writers (sync/index jobs, editors) that may touch the source during the copy

Example fix

// before: single attempt, mismatch fails the whole job
copy(...).await?;

// after: retry once on checksum mismatch, then escalate
for attempt in 0..2 {
    match copy(...).await {
        Err(e) if e.kind() == std::io::ErrorKind::InvalidData && attempt == 0 => continue,
        other => break other?,
    }
}
Defensive patterns

Strategy: retry

Validate before calling

// Before a critical copy, confirm the source is quiescent (two reads, same digest)
let h1 = blake3::hash(&tokio::fs::read(src).await?);
tokio::time::sleep(Duration::from_millis(250)).await;
let h2 = blake3::hash(&tokio::fs::read(src).await?);
assert_eq!(h1, h2, "source is being modified concurrently; copying now will fail verification");

Try / catch

match copy_result {
    Err(e) if e.kind() == std::io::ErrorKind::InvalidData && e.to_string().contains("Checksum") => {
        retry_with_backoff(/* once */).await // transient media glitch most of the time
    }
    other => other?,
}

Prevention

When it happens

Trigger: Source file modified concurrently while being read (hash computed over a moving target); failing disk or flaky USB cable corrupting writes mid-transfer; destination on a buggy FUSE/network filesystem that alters data; oversized writes silently truncated; antivirus/backup agents touching the file between write and flush.

Common situations: Copying photos off a camera SD card while the camera is still mounted for writing; copying to a failing HDD or a saturated network share; exotic filesystems (exFAT on some kernels, network volumes) with write quirks.

Related errors


AI-assisted analysis of spacedriveapp/spacedrive@6dfeccf211 (2026-08-16). Data as JSON: /api/errors/fda94cee88810de8. Report an issue: GitHub.