{"record":{"id":"416582872e3a54c2","repo":"sinelaw/fresh","slug":"original-file-size-mismatch-expected-got","errorCode":null,"errorMessage":"Original file size mismatch: expected {}, got {}","messagePattern":"Original file size mismatch: expected (.+?), got (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/fresh-editor/src/services/recovery/storage.rs","lineNumber":486,"sourceCode":"    /// the full modified content.\n    pub fn reconstruct_from_chunks(&self, id: &str, original_file: &Path) -> io::Result<Vec<u8>> {\n        let chunked_data = self.read_chunked_content(id)?.ok_or_else(|| {\n            io::Error::new(io::ErrorKind::NotFound, \"Chunked recovery data not found\")\n        })?;\n\n        // Read original file\n        let original_content = fs::read(original_file)?;\n\n        tracing::debug!(\n            \"reconstruct_from_chunks: original_file={:?}, file_size_on_disk={}, expected_original_size={}\",\n            original_file,\n            original_content.len(),\n            chunked_data.original_size\n        );\n\n        // Verify original file size matches what we expected\n        if original_content.len() != chunked_data.original_size {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                format!(\n                    \"Original file size mismatch: expected {}, got {}\",\n                    chunked_data.original_size,\n                    original_content.len()\n                ),\n            ));\n        }\n\n        // Apply chunks to reconstruct content\n        let mut result = Vec::with_capacity(chunked_data.final_size);\n        let mut original_pos = 0;\n\n        for chunk in &chunked_data.chunks {\n            // Copy unchanged content before this chunk\n            if chunk.offset > original_pos {\n                result.extend_from_slice(&original_content[original_pos..chunk.offset]);\n            }","sourceCodeStart":468,"sourceCodeEnd":504,"githubUrl":"https://github.com/sinelaw/fresh/blob/67894ca5463dbd7a89bb31add4627c27d6b79d83/crates/fresh-editor/src/services/recovery/storage.rs#L468-L504","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Restore the original file to the size/contents recorded in the recovery metadata (e.g. git stash or checkout the matching revision) and retry.","If the current file is intentionally newer, skip chunk-based reconstruction and recover only the chunk contents manually.","Log and surface both expected and actual sizes to decide whether to force-recover; do not blindly apply chunks to a changed base."],"exampleFix":"// before\nlet content = storage.reconstruct_from_chunks(&id, &original)?;\n// after\nlet actual = fs::metadata(&original)?.len();\nlet expected = storage.recorded_original_size(&id)?;\nif actual != expected {\n    eprintln!(\"original changed since crash ({expected} -> {actual}); skipping reconstruction\");\n    return Ok(None);\n}\nlet content = storage.reconstruct_from_chunks(&id, &original)?;","handlingStrategy":"validation","validationCode":"let actual = fs::metadata(original_file)?.len();\nlet expected = storage.recorded_original_size(id)?;\nif actual != expected {\n    eprintln!(\"original changed since crash: expected {expected}, got {actual}\");\n    return Ok(None);\n}","typeGuard":"fn base_unchanged(storage: &RecoveryStorage, id: &str, original: &Path) -> bool {\n    match (fs::metadata(original), storage.recorded_original_size(id)) {\n        (Ok(m), Ok(expected)) => m.len() == expected,\n        _ => false,\n    }\n}","tryCatchPattern":null,"preventionTips":["Do not edit or save the original file until crash recovery has been completed","Record and compare a content hash, not just size, for stronger base verification","Restore the file to its pre-crash state (VCS) before applying recovery chunks"],"tags":["recovery","consistency","file-size","data-integrity"],"backgroundTag":"checksum-mismatch","analyzedSha":"67894ca5463dbd7a89bb31add4627c27d6b79d83","analyzedAt":"2026-09-13T15:04:03.701Z","contentChangedAt":"2026-09-13T15:04:03.701Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}