AlexsJones/llmfit · error
JSON serialization failed
Error message
JSON serialization failed
What it means
An .expect() inside ModelQualityResult::display() (quality.rs) around serde_json::to_string_pretty of a json!-built Value. A Value constructed via the json! macro serializes successfully unless it contains non-finite floats — serde_json rejects NaN/Infinity with 'float must be finite'. Since quality/speed/composite scores are f64 computed from model responses, NaN propagation (e.g. averaging over zero tests, or a rubric score of 0/0) is the realistic trigger for this panic.
Source
Thrown at llmfit-core/src/quality.rs:594
/// Print results as JSON.
pub fn display_json(&self) {
let json = serde_json::json!({
"quality_benchmark": {
"model": self.model,
"provider": self.provider,
"overall": {
"quality": self.overall_quality,
"speed": self.overall_speed,
"composite": self.overall_composite,
},
"role_scores": self.roles,
"test_results": self.test_results,
}
});
println!(
"{}",
serde_json::to_string_pretty(&json).expect("JSON serialization failed")
);
}
}
impl RoutingRecommendation {
/// Print a routing matrix row.
pub fn display_row(&self) {
let note_str = self
.note
.as_deref()
.map(|n| format!(" ({})", n))
.unwrap_or_default();
println!(
" {:<17} -> {:<30} q={:.1} s={:.1} c={:.1}{}",
self.role, self.model, self.quality, self.speed, self.composite, note_str
);
}
}View on GitHub (pinned to acc7e40c3a)
Solutions
- Sanitize scores before display: map non-finite values to 0.0 (or serialize them as null) with a small helper applied to overall_quality/overall_speed/overall_composite and role/test scores
- Fix the upstream NaN source — typically a division by a test count that can be zero — so aggregates are computed only over successful tests
- Reproduce with `llmfit quality --model ... --json` against the failing endpoint and inspect which score field is NaN before printing
Example fix
// before (quality.rs)
println!("{}", serde_json::to_string_pretty(&json).expect("JSON serialization failed"));
// after — clamp non-finite floats so Value is always serializable
fn finite(v: f64) -> f64 { if v.is_finite() { v } else { 0.0 } }
// ...use finite(self.overall_quality), finite(self.overall_speed), finite(self.overall_composite) when building `json`... Defensive patterns
Strategy: validation
Validate before calling
// before printing, assert all scores are finite
fn all_finite(r: &ModelQualityResult) -> bool {
r.overall_quality.is_finite() && r.overall_speed.is_finite() && r.overall_composite.is_finite()
}
assert!(all_finite(&result), "non-finite score — refusing to serialize NaN/Inf"); Type guard
fn finite_score(v: f64) -> Option<f64> {
v.is_finite().then_some(v)
} Prevention
- Compute aggregates only over successful tests; guard divisions with a zero-count check
- Clamp scores through a finite() helper before building JSON values
- Add a unit test serializing a result containing a NaN score to catch regressions
When it happens
Trigger: A quality run where a scoring computation produces NaN or Infinity (division by zero when no tests succeeded, an errored test contributing NaN that is then averaged) and display() is called to print the JSON summary.
Common situations: Benchmarking an endpoint that returns empty/garbage responses so role scores degrade to NaN; refactoring the composite-score formula and introducing an unchecked division.
Related errors
- embedded use_case_benchmarks.json is invalid
- embedded benchmarks.yaml is invalid
- valid MLX suffix regex
- CARGO_MANIFEST_DIR
- OUT_DIR
AI-assisted analysis of AlexsJones/llmfit@acc7e40c3a (2026-08-17).
Data as JSON: /api/errors/9eb66e2c551a8b5e.
Report an issue: GitHub.