{"record":{"id":"e9b491ed8e2a66a8","repo":"Hmbown/CodeWhale","slug":"invaliddata","errorCode":"InvalidData","errorMessage":"invalid approval receipt at line {}: {err}","messagePattern":"invalid approval receipt at line (.+?): (.+?)","errorType":"exception","errorClass":"std::io::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/approval_log.rs","lineNumber":226,"sourceCode":"        match OpenOptions::new().read(true).open(path) {\n            Ok(file) => Ok(Some(file)),\n            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),\n            Err(err) => Err(err),\n        }\n    }\n\n    fn load_unlocked(&self, session_id: &str) -> io::Result<Vec<ApprovalReceipt>> {\n        let path = self.log_path(session_id)?;\n        let file = match File::open(path) {\n            Ok(file) => file,\n            Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(Vec::new()),\n            Err(err) => return Err(err),\n        };\n        let mut receipts = Vec::new();\n        for (index, line) in BufReader::new(file).lines().enumerate() {\n            let line = line?;\n            let receipt = serde_json::from_str(&line).map_err(|err| {\n                io::Error::new(\n                    io::ErrorKind::InvalidData,\n                    format!(\"invalid approval receipt at line {}: {err}\", index + 1),\n                )\n            })?;\n            receipts.push(receipt);\n        }\n        ApprovalReplay::from_receipts(&receipts)\n            .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;\n        Ok(receipts)\n    }\n\n    pub(crate) fn load(&self, session_id: &str) -> io::Result<Vec<ApprovalReceipt>> {\n        if !self.log_path(session_id)?.exists() {\n            return Ok(Vec::new());\n        }\n        let Some(lock_file) = self.open_existing_lock_file(session_id)? else {\n            // Imported or legacy snapshots can contain a receipt log without\n            // its ephemeral lock file. Preserve read-only session loading;","sourceCodeStart":208,"sourceCodeEnd":244,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/approval_log.rs#L208-L244","documentation":"ApprovalLog::load_unlocked reads <sessions>/<session_id>/approval_receipts.jsonl line by line, parsing each line as a JSON ApprovalReceipt. Any line serde_json cannot decode produces InvalidData with the 1-based line number and the underlying serde error. A missing log file is Ok(empty); a present but malformed one is fatal for loading/replaying that session's approvals. After parsing, ApprovalReplay::from_receipts can fail similarly if the receipts are mutually inconsistent.","triggerScenarios":"Loading a session whose approval_receipts.jsonl contains a hand-edited line, a truncated final line (crash or disk-full during append), a blank line, non-JSON text, or receipts written by an older/newer schema version that serde_json::from_str rejects.","commonSituations":"Upgrading/downgrading the binary across a receipt-format change; users editing or merging log files by hand; a killed process leaving a partial last line; syncing the sessions dir through a tool that mangled encoding.","solutions":["Open <home>/.codewhale/sessions/<session_id>/approval_receipts.jsonl, jump to the reported line (cat -n or jq), and fix or delete the malformed line","If the session is disposable, delete that session's directory so an empty log is recreated and approvals re-prompt","If the file was never touched, capture the full serde error and report a bug: the writer must only emit parseable receipts","After a version change, start a fresh session or resume so the current schema rewrites the log"],"exampleFix":"# before\n# line 17 of approval_receipts.jsonl is truncated garbage from a crash\n\n# after: drop the corrupt line and re-verify\nsed -i '17d' ~/.codewhale/sessions/<session_id>/approval_receipts.jsonl\ncodewhale sessions resume <session_id>","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match approval_log.load(sid) {\n    Err(e) if e.kind() == io::ErrorKind::InvalidData => {\n        // e message names the 1-based line: quarantine the file, reset the session,\n        // never silently drop approvals\n        log::warn!(\"corrupt approval log: {e}; session {sid} will re-prompt\");\n    }\n    other => other?,\n}","preventionTips":["Never hand-edit approval_receipts.jsonl","Write receipts atomically/append-complete (newline-terminated) so a crash cannot leave a partial line","Version the receipt schema so cross-version loads fail with a clear message"],"tags":["json","jsonl","parsing","approval-log","corruption"],"backgroundTag":"corrupt-json-file","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}