{"record":{"id":"7430ed5e353d92f0","repo":"xai-org/grok-build","slug":"serde-json-serialization-error-for-summary","errorCode":null,"errorMessage":"<serde_json serialization error for Summary>","messagePattern":"<serde_json serialization error for Summary>","errorType":"validation","errorClass":"std::io::Error","httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-shell/src/session/storage/summary_write.rs","lineNumber":419,"sourceCode":"        .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\nfn restore_summary_mtime(path: &Path, mtime: std::time::SystemTime) -> io::Result<()> {\n    #[cfg(test)]\n    if RESTORE_MTIME_FAULT.replace(false) {\n        return Err(io::Error::other(\"injected mtime restore failure\"));\n    }","sourceCodeStart":401,"sourceCodeEnd":437,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-shell/src/session/storage/summary_write.rs#L401-L437","documentation":"write_summary_atomic serializes the Summary struct to pretty JSON before atomically writing it; a serde_json serialization failure (e.g. a non-string map key or unserializable value inside Summary) is wrapped as io::ErrorKind::InvalidData. With a plain derive-based struct this is rare and usually indicates a Map with non-string keys or a custom Serialize impl that fails.","triggerScenarios":"Calling write_summary_atomic (via repair_worktree_identity or read_modify_write) with a Summary containing data serde_json cannot represent — e.g. a HashMap with non-string keys, an untagged enum hitting an unserializable variant, or a custom Serialize impl returning an error.","commonSituations":"Introducing a BTreeMap<HashMap<i32,_>,..> or serde_json::Value::Number-typed key into Summary; nesting types with non-string map keys; building Summary from arbitrary parsed JSON with wrong key types.","solutions":["Inspect the inner serde error message to find the unserializable field","Change non-string map keys to String (or use #[serde(with)] helpers)","Ensure all Summary fields' types implement Serialize compatibly with JSON","Add a unit test that serializes a fully-populated Summary to catch regressions"],"exampleFix":"// before\nstruct Summary { meta: HashMap<Uuid, String> }\n// after\nstruct Summary { meta: HashMap<String, String> } // or BTreeMap<String, _> with uuid::Uuid keys via serde\nlet meta: HashMap<String, String> = original.into_iter().map(|(k, v)| (k.to_string(), v)).collect();","handlingStrategy":"try-catch","validationCode":"// pre-validate: ensure all map keys in data feeding Summary are strings\nassert!(summary.meta.keys().all(|k| k.parse::<uuid::Uuid>().is_ok() || k.is_empty()) || true); // prefer converting keys upstream\ntype Check = fn(&Summary) -> Result<(), serde_json::Error>;\nlet validate: Check = |s| serde_json::to_value(s).map(|_| ());","typeGuard":"fn serializable(s: &Summary) -> bool {\n    serde_json::to_vec_pretty(s).is_ok()\n}","tryCatchPattern":"match write_summary_atomic(&path, &summary) {\n    Ok(()) => (),\n    Err(e) if e.kind() == io::ErrorKind::InvalidData => {\n        eprintln!(\"Summary not JSON-serializable: {e}\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Keep Summary field types JSON-friendly (string keys in maps)","Add a round-trip serialization unit test for a fully populated Summary","Avoid embedding serde_json::Value with arbitrary user data without normalization","Convert Uuid/i32 map keys to String before storing in Summary"],"tags":["serialization","serde","io"],"backgroundTag":"json-serialization-failed","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}