astrid-runtime/astrid · error

corpus input changed while its baseline snapshot was capture

Error message

corpus input changed while its baseline snapshot was captured

What it means

`snapshot_file` hashes a file while streaming it and compares the byte count it saw (`snapshot.logical_bytes`) with the size taken before reading (`expected_bytes`). A mismatch means the file was modified concurrently while the baseline snapshot was being captured, so the snapshot is torn/inconsistent and the library aborts.

Source

Thrown at crates/astrid-storage-chunker-evidence/src/corpus.rs:527

}

fn include_walker_entry(recursive: bool, depth: usize, is_directory: bool, name: &str) -> bool {
    !recursive || depth != 1 || !is_directory || !EXCLUDED_TOP_LEVEL_DIRECTORIES.contains(&name)
}

fn snapshot_file(path: &Path) -> Result<FileSnapshot> {
    let file = File::open(path)
        .with_context(|| format!("open corpus input for snapshot {}", path.display()))?;
    let expected_bytes = file
        .metadata()
        .with_context(|| format!("stat corpus input {}", path.display()))?
        .len();
    let mut reader = HashingReader::new(BufReader::with_capacity(READER_CAPACITY, file));
    std::io::copy(&mut reader, &mut std::io::sink())
        .with_context(|| format!("snapshot corpus input {}", path.display()))?;
    let snapshot = reader.finish();
    if snapshot.logical_bytes != expected_bytes {
        bail!("corpus input changed while its baseline snapshot was captured");
    }
    Ok(snapshot)
}

fn validate_label(label: &str) -> Result<()> {
    if label.is_empty()
        || !label
            .bytes()
            .all(|byte| byte.is_ascii_lowercase() || byte.is_ascii_digit() || byte == b'-')
    {
        bail!("corpus label must contain only lowercase ASCII letters, digits, and hyphens");
    }
    Ok(())
}

fn validate_relative_git_path(path: &Path) -> Result<()> {
    if path.as_os_str().is_empty()
        || path.is_absolute()

View on GitHub (pinned to affd8760f4)

Solutions

  1. Ensure no other process writes to the corpus while the snapshot runs; stop generators/sync daemons first
  2. Copy the corpus to a stable, read-only location and snapshot the copy
  3. Re-run the snapshot; if it keeps failing, find the writer with `lsof <path>` or `fuser`

Example fix

// before
let snap = snapshot_file(&path, path.metadata()?.len())?; // file still being written
// after
std::fs::copy(&path, &stable_copy)?; // freeze input first
let snap = snapshot_file(&stable_copy, stable_copy.metadata()?.len())?;
Defensive patterns

Strategy: validation

Validate before calling

let before = std::fs::metadata(path)?.len();
snapshot_file(path, before)?;
if std::fs::metadata(path)?.len() != before { /* file changed again; retry */ }

Type guard

fn stable_size(path: &Path, probes: usize) -> Option<u64> {
    let mut last = std::fs::metadata(path).ok()?.len();
    for _ in 0..probes {
        std::thread::sleep(std::time::Duration::from_millis(50));
        let now = std::fs::metadata(path).ok()?.len();
        if now != last { last = now; }
    }
    Some(last)
}

Try / catch

match snapshot_file(&path, expected_len) {
    Ok(snap) => snap,
    Err(e) if e.to_string().contains("changed while its baseline snapshot") => {
        eprintln!("{path:?} is being written; waiting and retrying");
        std::thread::sleep(Duration::from_secs(1));
        retry_snapshot(&path)?
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: A file is written, truncated, appended, or rotated between the `metadata().len()` read and the completion of the `std::io::copy` hash inside `snapshot_file` (called by `Input::File`, `collect_files`, `validate_current_file`).

Common situations: Corpus files being regenerated by another process during benchmark setup, log files still being appended to, editors/tmp-file swaps (`mv` atomic renames) landing mid-snapshot, or files on actively-changing network shares.

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


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/076789dd7f73beeb. Report an issue: GitHub.