Hmbown/CodeWhale · error

Fleet artifact grew while being read

Error message

Fleet artifact grew while being read

What it means

During streaming verification, read_verified accumulates the byte count and asserts it never exceeds the size captured from file metadata at open time. If the file grew while being read (bytes appended between the metadata read and the streaming loop), verification aborts rather than hashing a moving target.

Solutions

  1. Ensure publication is complete before verification — coordinate with the writer or wait for the run to settle.
  2. Stop any process appending to files under the Fleet workspace; artifacts are immutable once published.
  3. Re-run verification after the writer finishes; re-capture the receipt if the final content is legitimate.
  4. Use unique per-run artifact paths so concurrent runs cannot share a file.
Defensive patterns

Strategy: retry

Try / catch

for attempt in 0..3 {
    match read_verified(ws, &artifact, preview_limit) {
        Ok(out) => return Ok(out),
        Err(e) if e.to_string().contains("grew while being read") && attempt < 2 => continue,
        Err(e) => return Err(e),
    }
}

Prevention

When it happens

Trigger: Another process/thread appends to the artifact file while read_verified is streaming it — total bytes read exceed the size recorded at open.

Common situations: A concurrent writer still flushing output while an evidence reader starts; a background job appending logs to the artifact path; racing publications that ignore the immutable-publication contract.

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 Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/bfb0a57cb3b7a122. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/fleet/artifacts.rs:79

    );
    let checksum = artifact
        .checksum
        .as_deref()
        .context("Fleet artifact has no recorded checksum")?;
    let mut hasher = Sha256::new();
    let mut preview = Vec::new();
    let mut buffer = [0_u8; 8192];
    let mut total = 0_u64;
    // The digest and returned preview consume exactly the same bytes from the
    // same opened file. A changed/replaced pathname is never reopened for data.
    let mut reader = (&file).take(size + 1);
    loop {
        let count = reader.read(&mut buffer)?;
        if count == 0 {
            break;
        }
        total += count as u64;
        ensure!(total <= size, "Fleet artifact grew while being read");
        hasher.update(&buffer[..count]);
        let remaining = preview_limit.saturating_sub(preview.len() as u64) as usize;
        preview.extend_from_slice(&buffer[..count.min(remaining)]);
    }
    ensure!(
        total == size && file.metadata()?.len() == size,
        "Fleet artifact size changed while being read"
    );
    ensure!(
        format!("sha256:{}", crate::hashing::hex_bytes(hasher.finalize())) == checksum,
        "Fleet artifact checksum does not match the recorded receipt"
    );
    Ok((preview, size))
}

#[cfg(test)]
mod tests {
    use super::*;

View on GitHub (pinned to 73e0f67d83)