Expand description
Structural non-finite-float guard for anything that implements Serialize.
§Why this exists
serde_json renders f64::NAN and ±f64::INFINITY as the JSON literal
null — JSON has no encoding for them and serde_json’s serializer takes
the lossy branch silently. A persisted model carrying one non-finite scalar
therefore writes without complaint and only fails on the way back in, as
invalid type: null, expected f64— an error that names neither the field nor the fit that produced it, and that surfaces arbitrarily far from the computation at fault (#2601).
§Why it is structural rather than a field list
The pre-existing guards (ensure_finite_scalar, validate_all_finite, and
the hand-maintained FittedModel::validate_numeric_finiteness) each name one
field. A hand-maintained enumeration over a struct with hundreds of optional
numeric fields cannot stay complete: every new field is opted OUT by default,
so the guard silently stops covering the payload as the payload grows. That
is exactly how #2601’s null reached a saved model.
ensure_serialized_floats_are_finite instead walks the value through
serde’s own data model — the same traversal the JSON writer performs — so
every float that would be written is checked, by construction, with no
per-field opt-in. It tracks the struct-field / map-key / sequence-index path
as it descends, so the error names the offending scalar the way the
scalar-at-a-time guards do:
payload.fit_result.blocks[3].edf must be finite, got NaNThe walk allocates nothing per scalar; only the current path (bounded by the nesting depth) and the borrowed field names are held.
Structs§
- NonFinite
Float - A non-finite float found at
pathwhile walking a serializable value.
Functions§
- ensure_
serialized_ floats_ are_ finite - Walk
valuethroughserde’s data model and fail on the FIRST non-finitef32/f64that a serializer would emit, reporting its path.