{"record":{"id":"ad9bb6c612231686","repo":"Hmbown/CodeWhale","slug":"err-session-manager","errorCode":null,"errorMessage":"{err}","messagePattern":"\\{err\\}","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/session_manager.rs","lineNumber":1254,"sourceCode":"/// Per-session offline queue file: `checkpoints/<session_id>.offline_queue.json`.\nconst OFFLINE_QUEUE_SUFFIX: &str = \".offline_queue.json\";\n\npub(crate) fn is_offline_queue_file(name: &str) -> bool {\n    name == OFFLINE_QUEUE_FILE || name.ends_with(OFFLINE_QUEUE_SUFFIX)\n}\n\nimpl SessionManager {\n    fn approval_receipt_store(&self) -> ApprovalReceiptStore {\n        ApprovalReceiptStore::new(self.sessions_dir.clone())\n    }\n\n    fn hydrate_approval_receipts(&self, session: &mut SavedSession) -> io::Result<()> {\n        let durable = self.approval_receipt_store().load(&session.metadata.id)?;\n        if !durable.is_empty() {\n            session.approval_receipts = durable;\n        }\n        ApprovalReplay::from_receipts(&session.approval_receipts)\n            .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;\n        Ok(())\n    }\n\n    /// Reconstruct completed approvals and interrupted unmatched asks for one\n    /// session without consulting the model transcript.\n    #[cfg_attr(not(test), expect(dead_code))]\n    pub(crate) fn replay_approvals(&self, session_id: &str) -> io::Result<ApprovalReplay> {\n        self.approval_receipt_store().replay(session_id)\n    }\n\n    fn validated_session_id<'a>(&self, id: &'a str) -> std::io::Result<&'a str> {\n        let trimmed = id.trim();\n        if trimmed.is_empty() {\n            return Err(std::io::Error::new(\n                std::io::ErrorKind::InvalidInput,\n                \"Session id cannot be empty\",\n            ));\n        }","sourceCodeStart":1236,"sourceCodeEnd":1272,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/session_manager.rs#L1236-L1272","documentation":"hydrate_approval_receipts loads durable approval receipts for a session and then replays them through ApprovalReplay::from_receipts; a replay failure is converted into io::ErrorKind::InvalidData. It means the stored receipt set is internally inconsistent (e.g. unmatched or malformed approval records) and cannot be reconstructed into a valid approval state. This fires during hydration for resume paths.","triggerScenarios":"Calling hydrate_approval_receipts when either approval_receipt_store().load succeeded but the receipts fail ApprovalReplay::from_receipts — corrupted, partial, or schema-drifted receipt entries in the store.","commonSituations":"Receipt files edited or truncated by a crash mid-write; receipts written by an older codewhale version whose format changed; manually copying approval receipt data between sessions.","solutions":["Read the chained source() error from ApprovalReplay to identify the malformed receipt","Remove or repair the offending approval receipt entries in the session's receipt store","Re-save the session so receipts are regenerated; or restore the receipt store from backup","Check for version drift: receipts written by an older release may need migration"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"ApprovalReplay::from_receipts(&session.approval_receipts).map_err(|e| format!(\"bad receipts: {e}\"))?;","typeGuard":null,"tryCatchPattern":"match manager.hydrate_approval_receipts(&mut session) {\n    Ok(()) => resume(session),\n    Err(e) => {\n        log::warn!(\"receipt replay failed: {e}; starting without durable approvals\");\n        session.approval_receipts.clear(); // fallback: drop corrupt receipts\n    }\n}","preventionTips":["Never hand-edit or copy approval receipt stores between sessions","Test receipt-store compatibility when upgrading across releases","Back up the data directory before manual cleanup"],"tags":["serialization","approval-receipts","rust","session"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T02:17:17.105Z"}