{"record":{"id":"5657b716d8cd3e06","repo":"Hmbown/CodeWhale","slug":"invalid-late-usage-deletion-marker","errorCode":null,"errorMessage":"invalid late usage deletion marker","messagePattern":"invalid late usage deletion marker","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/session_manager.rs","lineNumber":1464,"sourceCode":"        }\n        Ok(paths)\n    }\n\n    /// A deletion marker and its stable lock survive deletion, without any\n    /// route or usage data. A captured callback must never recreate the ledger.\n    fn late_usage_is_deleted(path: &Path) -> io::Result<bool> {\n        use std::io::Read as _;\n        let tombstone = match open_private_read_file(&path.with_extension(\"deleted\")) {\n            Ok(file) => file,\n            Err(error) if error.kind() == io::ErrorKind::NotFound => return Ok(false),\n            Err(error) => return Err(error),\n        };\n        let mut marker = Vec::with_capacity(LATE_USAGE_DELETED.len());\n        tombstone\n            .take(u64::try_from(LATE_USAGE_DELETED.len()).unwrap_or(u64::MAX) + 1)\n            .read_to_end(&mut marker)?;\n        if marker != LATE_USAGE_DELETED {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                \"invalid late usage deletion marker\",\n            ));\n        }\n        Ok(true)\n    }\n\n    fn write_late_usage_ledger(path: &Path, ledger: &LateUsageLedger) -> io::Result<()> {\n        let bytes = serde_json::to_vec(ledger)\n            .map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))?;\n        if u64::try_from(bytes.len()).unwrap_or(u64::MAX) > MAX_LATE_USAGE_LEDGER_BYTES {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                \"late usage ledger exceeds its size bound\",\n            ));\n        }\n        write_atomic(path, &bytes)\n    }","sourceCodeStart":1446,"sourceCodeEnd":1482,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/session_manager.rs#L1446-L1482","documentation":"This io::Error with ErrorKind::InvalidData is raised when reading the tombstone file that marks a session as late-usage-deleted: the file's contents must exactly equal the marker bytes `codewhale-session-deleted-v1\\n` (LATE_USAGE_DELETED). If the file holds anything else, the library refuses to trust the tombstone because a corrupted or hand-edited file could otherwise be mistaken for a valid deletion record. It surfaces from the session manager's deletion-marker validation path in crates/tui/src/session_manager.rs:1464.","triggerScenarios":"Calling the session manager's late-usage tombstone check when the tombstone file exists but its bytes differ from LATE_USAGE_DELETED — e.g. a truncated read, a partial write, the marker version string changed between Codewhale versions, or the file was edited/overwritten externally (read path does `file.take(len+1).read_to_end` then compares to the constant).","commonSituations":"Upgrading/downgrading Codewhale so the marker version suffix (`-v1`) no longer matches; a crash or disk-full during a previous atomic write leaving partial content; manually inspecting or touching files under the sessions directory with an editor that adds a trailing newline, BOM, or rewrites bytes; copying session state between machines via a tool that mangles the marker.","solutions":["Delete the corrupted tombstone file so the session is no longer marked deleted, then let Codewhale recreate state normally.","Restore the file to the exact marker bytes `codewhale-session-deleted-v1\\n` if it was accidentally modified (printf 'codewhale-session-deleted-v1\\n' > tombstone).","Check for version mismatch: if Codewhale was upgraded/downgraded, the marker constant may have changed; re-sync session files from the matching version or clear the stale tombstones.","Verify disk health/free space — a partial write during the original atomic write is a common corruption source; re-run the affected session operation."],"exampleFix":"// before: tombstone file edited externally, contains \"codewhale-session-deleted-v1\\n\\n\"\n// after: restore exact marker bytes\n$ printf 'codewhale-session-deleted-v1\\n' > ~/.local/state/codewhale/sessions/<id>.tombstone","handlingStrategy":"validation","validationCode":"let marker = std::fs::read(tombstone_path)?;\nif marker != b\"codewhale-session-deleted-v1\\n\" {\n    // treat as corrupt: remove or restore the file before the library reads it\n    let _ = std::fs::remove_file(tombstone_path);\n}","typeGuard":"fn is_valid_tombstone(bytes: &[u8]) -> bool {\n    bytes == b\"codewhale-session-deleted-v1\\n\"\n}","tryCatchPattern":"match manager.check_late_usage_tombstone(path) {\n    Ok(deleted) => { /* proceed */ }\n    Err(e) if e.kind() == io::ErrorKind::InvalidData => {\n        // corrupt marker: drop the tombstone and re-run\n        let _ = std::fs::remove_file(path);\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Never open or save tombstone files with text editors; they may add BOMs or trailing bytes.","Copy session state with byte-exact tools (cp, rsync), not converters that alter line endings.","Keep all Codewhale instances on the same version so marker constants agree.","Monitor disk-full/crash conditions; verify atomic writes completed after an unclean shutdown."],"tags":["io","invalid-data","corruption","session-state"],"backgroundTag":"checksum-mismatch","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}