BoundaryML/baml · error · io::Error

profiling usage ledger checksum mismatch

Error message

profiling usage ledger checksum mismatch

What it means

The usage ledger stores its value plus a SHA-256 checksum over the first 16 bytes (magic + 8-byte big-endian counter). read_usage_state recomputes the digest and compares it to bytes[16..]; a mismatch raises InvalidData 'profiling usage ledger checksum mismatch', meaning the ledger content was altered or corrupted after it was written.

Source

Thrown at baml_language/crates/bex_prof_store/src/prof/backend/store.rs:1664

    let mut total = USAGE_STATE_BYTES;
    scan(root, root, &mut total)?;
    Ok(total)
}

fn read_usage_state(root: &Path) -> io::Result<u64> {
    let usage_state_len = usize::try_from(USAGE_STATE_BYTES).expect("fixed usage state fits usize");
    let mut bytes = Vec::with_capacity(usage_state_len);
    File::open(root.join("usage.state"))?.read_to_end(&mut bytes)?;
    if bytes.len() != usage_state_len || &bytes[..8] != USAGE_MAGIC {
        return Err(io::Error::new(
            io::ErrorKind::InvalidData,
            "invalid profiling usage ledger",
        ));
    }
    let expected: [u8; 32] = Sha256::digest(&bytes[..16]).into();
    if bytes[16..] != expected {
        return Err(io::Error::new(
            io::ErrorKind::InvalidData,
            "profiling usage ledger checksum mismatch",
        ));
    }
    Ok(u64::from_be_bytes(
        bytes[8..16].try_into().expect("fixed-width usage"),
    ))
}

fn write_usage_state(root: &Path, usage: u64, platform: &dyn StorePlatform) -> io::Result<()> {
    let usage_state_len = usize::try_from(USAGE_STATE_BYTES).expect("fixed usage state fits usize");
    let mut bytes = Vec::with_capacity(usage_state_len);
    bytes.extend_from_slice(USAGE_MAGIC);
    bytes.extend_from_slice(&usage.to_be_bytes());
    let checksum: [u8; 32] = Sha256::digest(&bytes).into();
    bytes.extend_from_slice(&checksum);
    let temporary = root.join("tmp/usage-state.pending");
    let mut file = OpenOptions::new()

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Delete usage.state so the store rebuilds the ledger from the actual on-disk segment sizes.
  2. Restore usage.state from a known-good backup.
  3. Check storage health (dmesg/SMART) if corruption recurs; run the store on reliable media.
  4. Do not hand-edit the ledger — always update usage through the store's own APIs so the checksum stays consistent.

Example fix

// shell
// before: usage.state checksum mismatch (edited counter)
// after
rm <store-root>/usage.state  # ledger is recomputed from segments on next open
Defensive patterns

Strategy: validation

Validate before calling

let bytes = fs::read(root.join("usage.state"))?;
let expected: [u8; 32] = Sha256::digest(&bytes[..16]).into();
if bytes.len() == 48 && bytes[16..] != expected {
    // checksum mismatch: delete the ledger so it is rebuilt from segments
}

Try / catch

match read_usage_state(&root) {
    Ok(usage) => usage,
    Err(e) if e.to_string().contains("checksum mismatch") => {
        let _ = fs::remove_file(root.join("usage.state"));
        rebuild_usage_from_segments(&root)
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Reading usage.state whose first 16 bytes (magic+counter) no longer match the stored 32-byte SHA-256 digest — e.g. hand-edited counter bytes, torn write, or bit rot in the first 16 bytes.

Common situations: Someone tried to tamper with the recorded usage counter; a crash/power loss during the ledger write left mismatched bytes; disk corruption; partial copy of the file.

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 BoundaryML/baml@bd85ce9dee (2026-09-12). Data as JSON: /api/errors/d8371e2a7e399d39. Report an issue: GitHub.