astrid-runtime/astrid · error

capsule entry ' ' size changed while hashing

Error message

capsule entry '{path}' size changed while hashing

What it means

Fired by hash_reader when the bytes actually read from a capsule entry differ from the tar header's declared size, meaning the archive entry is truncated, corrupted, or being mutated while the digest is computed.

Solutions

  1. Re-download or rebuild the capsule archive; it is corrupt or was truncated
  2. Verify the storage medium and free disk space
  3. Re-run the operation after no other process is writing the file
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at crates/astrid-build/src/artifact.rs:320 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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

Appendix: source

Thrown at crates/astrid-build/src/artifact.rs:320

        bail!("capsule archive contains an empty path");
    }
    Ok(parts.join("/"))
}

fn hash_reader(path: String, size: u64, reader: &mut impl Read) -> anyhow::Result<ContentRecord> {
    let mut hasher = blake3::Hasher::new();
    let mut read = 0_u64;
    let mut buffer = [0_u8; 16 * 1024];
    loop {
        let count = reader.read(&mut buffer)?;
        if count == 0 {
            break;
        }
        hasher.update(&buffer[..count]);
        read = read.saturating_add(count as u64);
    }
    if read != size {
        bail!("capsule entry '{path}' size changed while hashing");
    }
    Ok(ContentRecord {
        path,
        size,
        hash: *hasher.finalize().as_bytes(),
    })
}

fn digest_records(mut records: Vec<ContentRecord>) -> anyhow::Result<String> {
    records.sort_unstable_by(|left, right| left.path.cmp(&right.path));
    if records.windows(2).any(|pair| pair[0].path == pair[1].path) {
        bail!("capsule content tree contains duplicate paths");
    }
    let mut hasher = blake3::Hasher::new();
    hasher.update(CONTENT_DOMAIN);
    for record in records {
        let path = record.path.as_bytes();
        hasher.update(&(path.len() as u64).to_le_bytes());

View on GitHub (pinned to affd8760f4)