sinelaw/fresh · error

Original file size mismatch: expected

Error message

Original file size mismatch: expected {}, got {}

What it means

reconstruct_from_chunks verifies that the current size of the original file equals original_size recorded in the chunked recovery metadata. The chunks are diffs against that exact base, so a different size means the base file changed since the recovery data was captured and reconstruction would produce corrupt content; hence InvalidData rather than NotFound.

Solutions

  1. Restore the original file to the size/contents recorded in the recovery metadata (e.g. git stash or checkout the matching revision) and retry.
  2. If the current file is intentionally newer, skip chunk-based reconstruction and recover only the chunk contents manually.
  3. Log and surface both expected and actual sizes to decide whether to force-recover; do not blindly apply chunks to a changed base.

Example fix

// before
let content = storage.reconstruct_from_chunks(&id, &original)?;
// after
let actual = fs::metadata(&original)?.len();
let expected = storage.recorded_original_size(&id)?;
if actual != expected {
    eprintln!("original changed since crash ({expected} -> {actual}); skipping reconstruction");
    return Ok(None);
}
let content = storage.reconstruct_from_chunks(&id, &original)?;
Defensive patterns

Strategy: validation

Validate before calling

let actual = fs::metadata(original_file)?.len();
let expected = storage.recorded_original_size(id)?;
if actual != expected {
    eprintln!("original changed since crash: expected {expected}, got {actual}");
    return Ok(None);
}

Type guard

fn base_unchanged(storage: &RecoveryStorage, id: &str, original: &Path) -> bool {
    match (fs::metadata(original), storage.recorded_original_size(id)) {
        (Ok(m), Ok(expected)) => m.len() == expected,
        _ => false,
    }
}

Prevention

When it happens

Trigger: reconstruct_from_chunks called when the original file was edited, truncated, saved, replaced, or synchronized (git checkout, rsync) after the recovery session recorded its size.

Common situations: User edits/saves the file after the editor crashed, then runs recovery; CI or sync tools touch the file between crash and recovery; restoring an older file version from VCS before recovering.

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 sinelaw/fresh@67894ca546 (2026-09-13). Data as JSON: /api/errors/416582872e3a54c2. Report an issue: GitHub.

Appendix: source

Thrown at crates/fresh-editor/src/services/recovery/storage.rs:486

    /// the full modified content.
    pub fn reconstruct_from_chunks(&self, id: &str, original_file: &Path) -> io::Result<Vec<u8>> {
        let chunked_data = self.read_chunked_content(id)?.ok_or_else(|| {
            io::Error::new(io::ErrorKind::NotFound, "Chunked recovery data not found")
        })?;

        // Read original file
        let original_content = fs::read(original_file)?;

        tracing::debug!(
            "reconstruct_from_chunks: original_file={:?}, file_size_on_disk={}, expected_original_size={}",
            original_file,
            original_content.len(),
            chunked_data.original_size
        );

        // Verify original file size matches what we expected
        if original_content.len() != chunked_data.original_size {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                format!(
                    "Original file size mismatch: expected {}, got {}",
                    chunked_data.original_size,
                    original_content.len()
                ),
            ));
        }

        // Apply chunks to reconstruct content
        let mut result = Vec::with_capacity(chunked_data.final_size);
        let mut original_pos = 0;

        for chunk in &chunked_data.chunks {
            // Copy unchanged content before this chunk
            if chunk.offset > original_pos {
                result.extend_from_slice(&original_content[original_pos..chunk.offset]);
            }

View on GitHub (pinned to 67894ca546)