Hmbown/CodeWhale · error · std::io::Error
InvalidData
InvalidData
Error message
invalid approval receipt at line {}: {err} What it means
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.
Source
Thrown at crates/tui/src/approval_log.rs:226
match OpenOptions::new().read(true).open(path) {
Ok(file) => Ok(Some(file)),
Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
Err(err) => Err(err),
}
}
fn load_unlocked(&self, session_id: &str) -> io::Result<Vec<ApprovalReceipt>> {
let path = self.log_path(session_id)?;
let file = match File::open(path) {
Ok(file) => file,
Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(Vec::new()),
Err(err) => return Err(err),
};
let mut receipts = Vec::new();
for (index, line) in BufReader::new(file).lines().enumerate() {
let line = line?;
let receipt = serde_json::from_str(&line).map_err(|err| {
io::Error::new(
io::ErrorKind::InvalidData,
format!("invalid approval receipt at line {}: {err}", index + 1),
)
})?;
receipts.push(receipt);
}
ApprovalReplay::from_receipts(&receipts)
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
Ok(receipts)
}
pub(crate) fn load(&self, session_id: &str) -> io::Result<Vec<ApprovalReceipt>> {
if !self.log_path(session_id)?.exists() {
return Ok(Vec::new());
}
let Some(lock_file) = self.open_existing_lock_file(session_id)? else {
// Imported or legacy snapshots can contain a receipt log without
// its ephemeral lock file. Preserve read-only session loading;View on GitHub (pinned to 0c42157ee5)
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
Example fix
# before # line 17 of approval_receipts.jsonl is truncated garbage from a crash # after: drop the corrupt line and re-verify sed -i '17d' ~/.codewhale/sessions/<session_id>/approval_receipts.jsonl codewhale sessions resume <session_id>
Defensive patterns
Strategy: try-catch
Try / catch
match approval_log.load(sid) {
Err(e) if e.kind() == io::ErrorKind::InvalidData => {
// e message names the 1-based line: quarantine the file, reset the session,
// never silently drop approvals
log::warn!("corrupt approval log: {e}; session {sid} will re-prompt");
}
other => other?,
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- unrecognised character {ch:?} in duration {s:?}
- invalid SHA256 manifest line {}: {trimmed}
- lane exit receipt {} exceeds {} bytes
- {} exceeds the tombstone size limit
- agy OAuth token JSON carries no access token member
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/e9b491ed8e2a66a8.
Report an issue: GitHub.