vectordotdev/vector · error

Could not convert number to JSON

Error message

Could not convert number to JSON

What it means

The `ToValue` implementation for `f32`/`f64` converts a float to a `serde_json::Number` via `Number::from_f64`, which returns `None` for non-finite values (NaN, +inf, -inf) since JSON cannot represent them, and then panics. It signals that a floating-point config value being serialized to the event/value model is not a valid JSON number.

Solutions

  1. Validate the float is finite before converting: `assert!(v.is_finite())` or return an error
  2. Clamp or replace non-finite values with a sentinel (e.g. 0.0 or a configured default) at config-parse time
  3. Fix the source computation producing NaN/inf (division by zero, overflow)
  4. If parsing user/env input, reject non-finite strings during config validation

Example fix

// before
let ratio = numerator / denominator;
config.threshold = ratio;
// after
let ratio = if denominator == 0.0 { 0.0 } else { numerator / denominator };
assert!(ratio.is_finite(), "threshold must be a finite number");
config.threshold = ratio;
Defensive patterns

Strategy: validation

Validate before calling

fn ensure_finite_json_number(v: f64) -> Result<f64, String> {
    if v.is_finite() { Ok(v) } else { Err(format!("value {v} is not a valid JSON number")) }
}

Type guard

fn is_json_safe_f64(v: &f64) -> bool { v.is_finite() }

Try / catch

match Number::from_f64(v) {
    Some(n) => Value::Number(n),
    None => return Err(anyhow::anyhow!("cannot serialize non-finite float {v}")),
}

Prevention

When it happens

Trigger: Calling `to_value()` on an `f32`/`f64` that is NaN or infinite — e.g. a config value computed at runtime, a default derived from a division by zero, or an instrument/metric constant built from non-finite math.

Common situations: Config values computed as `0.0/0.0` (NaN) or overflow to infinity (e.g. `f64::MAX * 2.0`); parsing user input like "inf"/"nan" into f64 config fields; interpolating environment-driven defaults that produce non-finite results.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of vectordotdev/vector@bdb87aeaa4 (2026-09-16). Data as JSON: /api/errors/6f42d9fa5a006359. Report an issue: GitHub.

Appendix: source

Thrown at lib/vector-config/src/stdlib.rs:201

            fn to_value(&self) -> Value {
                let into = $into;
                Value::Number(into(*self))
            }
        }
    };
}

impl_configurable_numeric!(u8 => Into::into);
impl_configurable_numeric!(u16 => Into::into);
impl_configurable_numeric!(u32 => Into::into);
impl_configurable_numeric!(u64 => Into::into);
impl_configurable_numeric!(usize => Into::into);
impl_configurable_numeric!(i8 => Into::into);
impl_configurable_numeric!(i16 => Into::into);
impl_configurable_numeric!(i32 => Into::into);
impl_configurable_numeric!(i64 => Into::into);
impl_configurable_numeric!(isize => Into::into);
impl_configurable_numeric!(f32 => |v| Number::from_f64(v as f64).expect("Could not convert number to JSON"));
impl_configurable_numeric!(f64 => |v| Number::from_f64(v).expect("Could not convert number to JSON"));
impl_configurable_numeric!(NonZeroU8 => |v: NonZeroU8| v.get().into());
impl_configurable_numeric!(NonZeroU16 => |v: NonZeroU16| v.get().into());
impl_configurable_numeric!(NonZeroU32 => |v: NonZeroU32| v.get().into());
impl_configurable_numeric!(NonZeroU64 => |v: NonZeroU64| v.get().into());
impl_configurable_numeric!(NonZeroI8 => |v: NonZeroI8| v.get().into());
impl_configurable_numeric!(NonZeroI16 => |v: NonZeroI16| v.get().into());
impl_configurable_numeric!(NonZeroI32 => |v: NonZeroI32| v.get().into());
impl_configurable_numeric!(NonZeroI64 => |v: NonZeroI64| v.get().into());
impl_configurable_numeric!(NonZeroUsize => |v: NonZeroUsize| v.get().into());

// Arrays and maps.
impl<T> Configurable for Vec<T>
where
    T: Configurable + ToValue + 'static,
{
    fn metadata() -> Metadata {
        T::metadata().convert()

View on GitHub (pinned to bdb87aeaa4)