Hmbown/CodeWhale · warning · io::Error
session accounting was deleted
Error message
session accounting was deleted
What it means
load_late_usage found the session's deletion marker on disk before reading the ledger, so it returns NotFound("session accounting was deleted") instead of loading a retired session's accounting. It distinguishes a deliberately deleted session from a merely missing file (which yields an empty/default ledger).
Solutions
- Handle ErrorKind::NotFound by treating the session's accounting as empty/absent and dropping references to the deleted session id.
- Refresh the session list after deletions so stale ids are not reused for reads.
- If the deletion was unintended, restore the session's accounting files from backup; do not just recreate empty files while the deleted marker persists.
- Route reads through load_late_usage rather than opening the ledger path directly so the deleted state is honored.
Example fix
// before
let ledger = manager.load_late_usage(&session_id)?;
// after
let ledger = match manager.load_late_usage(&session_id) {
Ok(l) => l,
Err(e) if e.kind() == std::io::ErrorKind::NotFound => LateUsageLedger::default(), // deleted
Err(e) => return Err(e),
}; Defensive patterns
Strategy: fallback
Validate before calling
// before loading, check the session id is still known
if !known_sessions.contains(session_id) { return LateUsageLedger::default(); } Type guard
fn is_accounting_deleted(err: &std::io::Error) -> bool {
err.kind() == std::io::ErrorKind::NotFound && err.to_string().contains("session accounting was deleted")
} Try / catch
let ledger = manager.load_late_usage(session_id).unwrap_or_else(|e| {
debug_assert!(is_accounting_deleted(&e) || e.kind() == std::io::ErrorKind::NotFound);
LateUsageLedger::default() // deleted session: treat as empty accounting
}); Prevention
- Drop cached session ids after deletion events; subscribe to session-list changes.
- Always read accounting through load_late_usage so the deleted marker is honored.
- Back up session accounting before deletion if the data may be needed again.
When it happens
Trigger: Calling load_late_usage(session_id) after the session was deleted — late_usage_is_deleted(path) returned true under the read lock, indicating the tombstone/deleted state.
Common situations: A UI view or metrics aggregation still holds a stale session_id after the user deleted that session; restoring an old snapshot references a session whose accounting was removed.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- session was deleted
- Codewhale home directory not found
- invalid late usage deletion marker
- late usage ledger exceeds its size bound
- late usage ledger exceeds its size bound
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/c9ff083da8349126.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/session_manager.rs:1655
let lock_file = match open_private_read_file(&lock_path) {
Ok(file) => file,
Err(error) if error.kind() == io::ErrorKind::NotFound => {
// Atomic replacement makes a copied ledger readable without
// creating a lock. No writer can have published a tombstone
// without first creating the stable lock.
return read(&path);
}
Err(error) => return Err(error),
};
let lock = fd_lock::RwLock::new(lock_file);
let _guard = lock.read()?;
read(&path)
}
fn load_late_usage(&self, session_id: &str) -> io::Result<LateUsageLedger> {
self.with_session_read_lock(session_id, |path| {
if Self::late_usage_is_deleted(path)? {
return Err(io::Error::new(
io::ErrorKind::NotFound,
"session accounting was deleted",
));
}
Self::load_late_usage_unlocked(path)
})
}
fn apply_late_usage_to_metadata(&self, metadata: &mut SessionMetadata) {
let ledger = match self.load_late_usage(&metadata.id) {
Ok(ledger) => ledger,
Err(_) => {
// The transcript is independent of optional accounting data.
// Keep a stable gap receipt even when this projection is later
// saved; loading it again must not invent another missing call.
let fingerprint = crate::cost_status::usage_source_fingerprint(&format!(
"late-usage-unavailable:{}",
crate::cost_status::usage_source_fingerprint(&metadata.id)View on GitHub (pinned to 73e0f67d83)