{"record":{"id":"f5ca826f887117ac","repo":"xai-org/grok-build","slug":"serde-json-deserialization-error-for-summary-json","errorCode":null,"errorMessage":"<serde_json deserialization error for summary.json>","messagePattern":"<serde_json deserialization error for summary\\.json>","errorType":"validation","errorClass":"std::io::Error","httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-shell/src/session/storage/summary_write.rs","lineNumber":414,"sourceCode":"fn open_lock_file(path: &Path) -> io::Result<File> {\n    OpenOptions::new()\n        .read(true)\n        .write(true)\n        .create(true)\n        .truncate(false)\n        .open(path)\n}\n\nfn read_summary(path: &Path) -> io::Result<Summary> {\n    let bytes = std::fs::read(path)?;\n    if bytes.is_empty() {\n        return Err(io::Error::new(\n            io::ErrorKind::InvalidData,\n            format!(\"summary.json is empty (0 bytes): {}\", path.display()),\n        ));\n    }\n    serde_json::from_slice::<Summary>(&bytes)\n        .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))\n}\n\nfn write_summary_atomic(summary_path: &Path, summary: &Summary) -> io::Result<()> {\n    let bytes = serde_json::to_vec_pretty(summary)\n        .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;\n    crate::session::storage::write_bytes_atomic(summary_path, &bytes)\n}\n\n#[cfg(test)]\nthread_local! {\n    static RESTORE_MTIME_FAULT: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };\n}\n\n#[cfg(test)]\npub(crate) fn fail_next_restore_summary_mtime() {\n    RESTORE_MTIME_FAULT.set(true);\n}\n","sourceCodeStart":396,"sourceCodeEnd":432,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-shell/src/session/storage/summary_write.rs#L396-L432","documentation":"read_summary deserializes the summary.json bytes into the Summary struct with serde_json; any shape mismatch becomes io::ErrorKind::InvalidData wrapping the serde error. The file exists and is non-empty but its JSON does not match the current Summary schema.","triggerScenarios":"Calling read_summary on a summary.json written by an older/newer version with different fields, a hand-edited file with invalid JSON or wrong types, or a partially-written (truncated mid-way) file that is non-empty but invalid JSON.","commonSituations":"Version upgrade/downgrade where Summary fields were renamed or made non-optional; manual editing of session metadata; interrupted legacy writes; a different tool overwrote summary.json with its own JSON.","solutions":["Read the wrapped serde error to identify the offending field, then fix or regenerate the summary.json","Delete the file and let the app recreate it, or restore from backup","Make newly added Summary fields #[serde(default)] so older files still deserialize","Pin/align app versions so writer and reader agree on the Summary schema"],"exampleFix":"// before\n#[derive(Serialize, Deserialize)]\nstruct Summary { title: String, new_field: String }\n// after\n#[derive(Serialize, Deserialize)]\nstruct Summary {\n    title: String,\n    #[serde(default)]\n    new_field: String,\n}","handlingStrategy":"validation","validationCode":"let bytes = std::fs::read(&path)?;\nlet ok = !bytes.is_empty()\n    && serde_json::from_slice::<serde_json::Value>(&bytes)\n        .map(|v| v.get(\"title\").is_some())\n        .unwrap_or(false);","typeGuard":"fn parses_as_summary(bytes: &[u8]) -> Option<Summary> {\n    serde_json::from_slice::<Summary>(bytes).ok()\n}","tryCatchPattern":"match read_summary(&path) {\n    Ok(s) => s,\n    Err(e) if e.kind() == io::ErrorKind::InvalidData => {\n        eprintln!(\"summary.json malformed: {e}\");\n        Summary::default()\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Add new Summary fields as #[serde(default)] to stay backward compatible","Validate summary.json after version upgrades before relying on it","Never hand-edit summary.json; regenerate through the app","Write only through write_summary_atomic so partial JSON never lands"],"tags":["io","serde","schema-mismatch","serialization"],"backgroundTag":"schema-validation-failed","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}