zeroclaw-labs/zeroclaw · error

providers.models.{profile_name}.pricing.{key}: value must no

Error message

providers.models.{profile_name}.pricing.{key}: value must not be NaN

What it means

Every value in a model profile's `pricing` map is checked with f64::is_nan(). TOML permits bare `nan` float literals, so a NaN can enter config directly, and NaN would silently poison all downstream cost arithmetic (every comparison against NaN is false). Validation rejects it up front, naming the offending pricing key.

Source

Thrown at crates/zeroclaw-config/src/schema.rs:21632

                validate_temperature(temp).map_err(|e| {
                    ::zeroclaw_log::record!(
                        WARN,
                        ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Reject)
                            .with_outcome(::zeroclaw_log::EventOutcome::Failure)
                            .with_attrs(::serde_json::json!({
                                "profile": profile_name,
                                "temperature": temp,
                                "error": format!("{}", e),
                            })),
                        "providers.models.<alias>.temperature rejected"
                    );
                    anyhow::Error::msg(format!("providers.models.{profile_name}.temperature: {e}"))
                })?;
            }

            for (key, value) in &profile.pricing {
                if value.is_nan() {
                    anyhow::bail!(
                        "providers.models.{profile_name}.pricing.{key}: value must not be NaN"
                    );
                }
                if *value < 0.0 {
                    anyhow::bail!(
                        "providers.models.{profile_name}.pricing.{key}: value must be >= 0.0 (got {value})"
                    );
                }
            }
        }

        // Non-fatal validation warnings: surfaced both via tracing (CLI sees
        // on stderr) and via Config::collect_warnings (gateway HTTP returns
        // structured to dashboard callers). Single source of truth lives in
        // collect_warnings; emit each one to tracing here so the existing
        // log behavior is preserved.
        for w in self.collect_warnings() {
            ::zeroclaw_log::record!(

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Replace nan with the real numeric price for the named key
  2. If the price is genuinely unknown, use 0.0 so cost estimates read zero rather than corrupting arithmetic — or omit the key
  3. Guard computed prices before writing config: skip or clamp values that fail is_finite()

Example fix

# before
[providers.models.gpt-x.pricing]
input = nan
output = 0.002

# after
[providers.models.gpt-x.pricing]
input = 0.001
output = 0.002
Defensive patterns

Strategy: validation

Validate before calling

fn pricing_precheck(cfg: &zeroclaw_config::Config) -> Result<(), String> {
    for (name, profile) in &cfg.providers.models.entries {
        for (key, value) in &profile.pricing {
            if value.is_nan() {
                return Err(format!("providers.models.{name}.pricing.{key} is NaN"));
            }
        }
    }
    Ok(())
}

Type guard

fn pricing_is_finite(pricing: &std::collections::HashMap<String, f64>) -> bool {
    pricing.values().all(|v| v.is_finite())
}

Try / catch

if let Err(err) = config.validate() {
    if err.to_string().contains("must not be NaN") {
        // replace the named pricing key with a real number (0.0 if unknown) and reload
    }
}

Prevention

When it happens

Trigger: Write `pricing = { input = nan }` (TOML nan literal) on any [providers.models.*] profile, or generate config programmatically from a computation that yields 0.0/0.0 or f64::NAN.

Common situations: Placeholder values for token prices the operator doesn't know yet; per-token math derived by dividing quoted prices; tooling that serializes floats without a finite-guard (serde_json rejects NaN, TOML does not — TOML configs are the leak path).

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/08d868260ae1df17. Report an issue: GitHub.