astrid-runtime/astrid · critical

BLAKE3 evidence collision with inconsistent lengths

Error message

BLAKE3 evidence collision with inconsistent lengths

What it means

insert_identity tracks unique content identities with their byte lengths and accumulates unique byte counts. If an identity already exists with a different recorded length, the map is inconsistent (or a hash collision occurred), so it bails rather than corrupting dedup statistics.

Solutions

  1. Re-hash and compare the record's bytes against the original to detect corruption.
  2. Rebuild the evidence/metrics state from source data.
  3. Investigate for true hash collision only if inputs are verified distinct yet same identity.
Defensive patterns

Strategy: try-catch

Validate before calling

if let Some(prev) = unique.get(&id) { assert_eq!(*prev, bytes.len() as u64, "length drift for identity"); }

Try / catch

match metrics.add_chunk_record(bytes, n) {
    Err(e) if e.to_string().contains("inconsistent lengths") => return Err(anyhow!("corrupted evidence: {e}")),
    other => other,
}

Prevention

When it happens

Trigger: add_record inserting a chunk/representation identity whose stored length differs from the current byte-slice length — from corrupted evidence, mutated record bytes after hashing, or an injected collision.

Common situations: Stale or truncated metrics persisted across runs; concurrent mutation of records between hashing and insertion; adversarial fuzz inputs.

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/14778bf03651fba2. Report an issue: GitHub.

Appendix: source

Thrown at crates/astrid-storage-chunker-evidence/src/metrics.rs:174

        })
    }
}

fn insert_identity(
    identities: &mut HashMap<[u8; 32], u64>,
    bytes: &[u8],
    unique_bytes: &mut u64,
) -> Result<()> {
    let length = u64::try_from(bytes.len())?;
    let identity = *blake3::hash(bytes).as_bytes();
    match identities.entry(identity) {
        std::collections::hash_map::Entry::Vacant(entry) => {
            entry.insert(length);
            *unique_bytes = checked_add(*unique_bytes, length, "unique byte count")?;
        },
        std::collections::hash_map::Entry::Occupied(entry) => {
            if *entry.get() != length {
                bail!("BLAKE3 evidence collision with inconsistent lengths");
            }
        },
    }
    Ok(())
}

fn deduplication(logical_bytes: u64, retained_bytes: u64) -> Result<Deduplication> {
    if retained_bytes > logical_bytes {
        bail!("retained bytes exceed logical bytes");
    }
    let saved_bytes = logical_bytes
        .checked_sub(retained_bytes)
        .ok_or_else(|| anyhow::anyhow!("retained bytes exceed logical bytes"))?;
    Ok(Deduplication {
        retained_bytes,
        saved_bytes,
        retained_basis_points: basis_points(retained_bytes, logical_bytes)?,
        saved_basis_points: basis_points(saved_bytes, logical_bytes)?,

View on GitHub (pinned to affd8760f4)