AlexsJones/llmfit · error
JSON serialization failed
Error message
JSON serialization failed
What it means
This is a panic from .expect("JSON serialization failed") on serde_json::to_string_pretty inside display_json_system, the handler for `llmfit system --json`. The input is a plain serde_json::Value envelope ({"system": system_json(specs)}), and to_string_pretty over a Value writes into an in-memory String with no fallible IO, so serde_json can only fail when a value violates the JSON data model (non-finite floats are already coerced to null by Value::from; map-length overflow needs >4 billion entries on 32-bit). The codebase deliberately treats this as an internal invariant per its AGENTS.md convention (expect for internal invariants only), so a panic here indicates a regression in the value produced by system_json/serve_shared::system_json rather than an environmental problem.
Source
Thrown at llmfit-tui/src/display.rs:498
})
.collect();
let table = Table::new(rows).with(Style::rounded()).to_string();
println!("{}", table);
}
// ────────────────────────────────────────────────────────────────────
// JSON output for machine consumption (OpenClaw skills, scripts, etc.)
// ────────────────────────────────────────────────────────────────────
/// Serialize system specs to JSON and print to stdout.
pub fn display_json_system(specs: &SystemSpecs) {
let output = serde_json::json!({
"system": system_json(specs),
});
println!(
"{}",
serde_json::to_string_pretty(&output).expect("JSON serialization failed")
);
}
/// Serialize system specs + model fits to JSON and print to stdout.
pub fn display_json_fits(specs: &SystemSpecs, fits: &[ModelFit]) {
let models: Vec<serde_json::Value> = fits.iter().map(fit_to_json).collect();
let output = serde_json::json!({
"system": system_json(specs),
"models": models,
});
println!(
"{}",
serde_json::to_string_pretty(&output).expect("JSON serialization failed")
);
}
/// Serialize system specs + model fits to JSON with llama.cpp commands and print to stdout.
pub fn display_json_fits_with_llamacpp(specs: &SystemSpecs, fits: &[ModelFit]) {View on GitHub (pinned to acc7e40c3a)
Solutions
- Re-run with RUST_BACKTRACE=1 to confirm the panic originates in display_json_system and not a downstream consumer of stdout.
- Run `llmfit system` without --json: if the plain table prints, hardware detection is fine and the fault is purely in the JSON envelope construction — inspect recent changes to serve_shared::system_json (llmfit-tui/src/serve_shared.rs).
- Check for newly added field types in the system section whose Serialize impl can error (maps with non-string keys, custom serializers returning Err).
- If it reproduces on a clean checkout, file a bug: this expect is documented as an unreachable invariant in this repo.
- As a maintainer, convert the expect into a match that prints to stderr and exits 1 if this path ever becomes reachable.
Example fix
// before
println!(
"{}",
serde_json::to_string_pretty(&output).expect("JSON serialization failed")
);
// after
match serde_json::to_string_pretty(&output) {
Ok(json) => println!("{json}"),
Err(e) => {
eprintln!("error: failed to serialize system JSON output: {e}");
std::process::exit(1);
}
} Defensive patterns
Strategy: validation
Validate before calling
// Pre-flight: prove the envelope serializes before the printing function panics.
let output = serde_json::json!({ "system": crate::serve_shared::system_json(specs) });
if serde_json::to_string_pretty(&output).is_err() {
eprintln!("system JSON payload is not serializable; refusing to print");
return;
}
display::display_json_system(specs); Try / catch
// Last-resort guard around a panicking display call (CLI process boundary):
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
display::display_json_system(&specs);
}));
if result.is_err() {
eprintln!("error: JSON output stage failed; this is a bug — please report it");
std::process::exit(1);
} Prevention
- Run `llmfit system --json | jq .` in CI so envelope regressions fail loudly before release.
- Keep serve_shared::system_json returning plain string/number/bool/array/object values; never insert map keys that are not strings.
- Add a unit test asserting serde_json::to_string_pretty on the built Value succeeds for a mocked SystemSpecs.
When it happens
Trigger: Running `llmfit system --json` (or any code path reaching display::display_json_system in llmfit-tui/src/main.rs:2808) after a change that makes the constructed Value unserializable — e.g. a custom Serialize impl in serve_shared::system_json that returns Err, or inserting non-string map keys into the envelope. On 32-bit targets, a map with more than u32::MAX entries would also fail.
Common situations: Almost never fires in released builds; typically appears during development after refactoring serve_shared::system_json or adding an exotic field type. CI that pipes JSON output through jq usually catches it first as an abrupt process abort with panic text on stderr.
Related errors
- valid MLX suffix regex
- fit_to_json returns an object
- files list is not empty
- embedded benchmarks.yaml is invalid
- JSON serialization failed
AI-assisted analysis of AlexsJones/llmfit@acc7e40c3a (2026-08-17).
Data as JSON: /api/errors/05053664e7365c2b.
Report an issue: GitHub.