{"record":{"id":"d1b583c50617d8c8","repo":"Hmbown/CodeWhale","slug":"session-file-missing-parseable-metadata-block","errorCode":null,"errorMessage":"session file missing parseable `metadata` block","messagePattern":"session file missing parseable `metadata` block","errorType":"exception","errorClass":"std::io::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/session_manager.rs","lineNumber":1661,"sourceCode":"        const PREFIX_BYTES: usize = 64 * 1024;\n        let mut file = fs::File::open(path)?;\n        let mut buf = Vec::with_capacity(PREFIX_BYTES);\n        file.by_ref()\n            .take(PREFIX_BYTES as u64)\n            .read_to_end(&mut buf)?;\n\n        if let Some(metadata) = extract_top_level_metadata(&buf) {\n            return Ok(metadata);\n        }\n\n        // Metadata wasn't extractable from the prefix (truncated mid-block,\n        // unusual key ordering, etc.). Read the rest and try again with the\n        // full buffer before giving up.\n        let mut rest = Vec::new();\n        file.read_to_end(&mut rest)?;\n        buf.extend_from_slice(&rest);\n        extract_top_level_metadata(&buf).ok_or_else(|| {\n            std::io::Error::new(\n                std::io::ErrorKind::InvalidData,\n                \"session file missing parseable `metadata` block\",\n            )\n        })\n    }\n\n    /// Delete a session by ID\n    pub fn delete_session(&self, id: &str) -> std::io::Result<()> {\n        let path = self.validated_session_path(id)?;\n        self.save_session_goal(id, None)?;\n        fs::remove_file(path)?;\n        self.clear_session_boot_owner(id);\n        let session_dir = self.sessions_dir.join(id.trim());\n        if session_dir.exists() {\n            fs::remove_dir_all(session_dir)?;\n        }\n        Ok(())\n    }","sourceCodeStart":1643,"sourceCodeEnd":1679,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/session_manager.rs#L1643-L1679","documentation":"Returned as io::ErrorKind::InvalidData when the session manager loads a session file whose top-level `metadata` block cannot be parsed. The loader first tries to extract metadata from an already-read prefix, then reads the remainder of the file and retries with the full buffer; this error means both attempts failed. The file on disk is therefore genuinely truncated or its metadata record is corrupted beyond what extract_top_level_metadata accepts.","triggerScenarios":"Resuming or listing a session whose .jsonl file was truncated mid-write (process kill, power loss, disk full during save), or whose metadata line was hand-edited, reordered, or written by an incompatible older format, so neither the prefix parse nor the full-buffer re-parse succeeds.","commonSituations":"App crashed while saving a session; disk-full during session write; sessions directory partially copied between machines or mutated by sync/backup tools; session files from a much older Codewhale version after an upgrade.","solutions":["Restore the affected session file from a backup or the previous synced copy","If the session is disposable, delete or move the file out of the sessions directory so the manager regenerates a clean one","Check free disk space and filesystem health to stop ongoing truncation during saves","If the metadata line looks well-formed but still fails extraction, preserve the file and report a bug against extract_top_level_metadata"],"exampleFix":"// before\nlet meta = manager.session_metadata(id)?; // one bad file aborts the whole listing\n\n// after\nlet meta = match manager.session_metadata(id) {\n    Ok(m) => m,\n    Err(e) if e.kind() == std::io::ErrorKind::InvalidData => continue, // skip corrupt file, keep listing\n    Err(e) => return Err(e),\n};","handlingStrategy":"try-catch","validationCode":"let raw = std::fs::read_to_string(&path)?;\nlet looks_complete = raw.lines().any(|l| l.contains(\"\\\"metadata\\\"\"));\nif !looks_complete {\n    // quarantine the file before the session loader rejects it\n    let _ = std::fs::rename(&path, path.with_extension(\"corrupt\"));\n}","typeGuard":"fn is_unparseable_session_metadata(e: &std::io::Error) -> bool {\n    e.kind() == std::io::ErrorKind::InvalidData\n        && e.to_string().contains(\"missing parseable `metadata` block\")\n}","tryCatchPattern":"match manager.load_session(id) {\n    Ok(s) => Ok(Some(s)),\n    Err(e) if is_unparseable_session_metadata(&e) => {\n        tracing::warn!(%id, \"skipping corrupt session file\");\n        Ok(None) // degrade gracefully, keep the session list usable\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Treat a failed/disk-full session save as fatal and surface it instead of leaving truncated files","Back up the sessions directory before version upgrades","Keep sync tools from touching the sessions directory while the app is running"],"tags":["rust","session-persistence","corrupted-file","jsonl","invalid-data"],"backgroundTag":"corrupt-session-file","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}