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

  1. Re-run with RUST_BACKTRACE=1 to confirm the panic originates in display_json_system and not a downstream consumer of stdout.
  2. 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).
  3. Check for newly added field types in the system section whose Serialize impl can error (maps with non-string keys, custom serializers returning Err).
  4. If it reproduces on a clean checkout, file a bug: this expect is documented as an unreachable invariant in this repo.
  5. 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

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


AI-assisted analysis of AlexsJones/llmfit@acc7e40c3a (2026-08-17). Data as JSON: /api/errors/05053664e7365c2b. Report an issue: GitHub.