xai-org/grok-build · error · std::io::Error
<serde_json deserialization error for summary.json>
Error message
<serde_json deserialization error for summary.json>
What it means
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.
Source
Thrown at crates/codegen/xai-grok-shell/src/session/storage/summary_write.rs:414
fn open_lock_file(path: &Path) -> io::Result<File> {
OpenOptions::new()
.read(true)
.write(true)
.create(true)
.truncate(false)
.open(path)
}
fn read_summary(path: &Path) -> io::Result<Summary> {
let bytes = std::fs::read(path)?;
if bytes.is_empty() {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("summary.json is empty (0 bytes): {}", path.display()),
));
}
serde_json::from_slice::<Summary>(&bytes)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
}
fn write_summary_atomic(summary_path: &Path, summary: &Summary) -> io::Result<()> {
let bytes = serde_json::to_vec_pretty(summary)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
crate::session::storage::write_bytes_atomic(summary_path, &bytes)
}
#[cfg(test)]
thread_local! {
static RESTORE_MTIME_FAULT: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
}
#[cfg(test)]
pub(crate) fn fail_next_restore_summary_mtime() {
RESTORE_MTIME_FAULT.set(true);
}
View on GitHub (pinned to bc7f02eddd)
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
Example fix
// before
#[derive(Serialize, Deserialize)]
struct Summary { title: String, new_field: String }
// after
#[derive(Serialize, Deserialize)]
struct Summary {
title: String,
#[serde(default)]
new_field: String,
} Defensive patterns
Strategy: validation
Validate before calling
let bytes = std::fs::read(&path)?;
let ok = !bytes.is_empty()
&& serde_json::from_slice::<serde_json::Value>(&bytes)
.map(|v| v.get("title").is_some())
.unwrap_or(false); Type guard
fn parses_as_summary(bytes: &[u8]) -> Option<Summary> {
serde_json::from_slice::<Summary>(bytes).ok()
} Try / catch
match read_summary(&path) {
Ok(s) => s,
Err(e) if e.kind() == io::ErrorKind::InvalidData => {
eprintln!("summary.json malformed: {e}");
Summary::default()
}
Err(e) => return Err(e),
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- <serde_json serialization error for Summary>
- failed to build request: {e}
- Compaction checkpoint file corrupt: {checkpoint_path}. Canno
- summary.json is empty (0 bytes): {}
- {}
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/f5ca826f887117ac.
Report an issue: GitHub.