{"record":{"id":"08d868260ae1df17","repo":"zeroclaw-labs/zeroclaw","slug":"providers-models-profile-name-pricing-key-val","errorCode":null,"errorMessage":"providers.models.{profile_name}.pricing.{key}: value must not be NaN","messagePattern":"providers\\.models\\.(.+?)\\.pricing\\.(.+?): value must not be NaN","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-config/src/schema.rs","lineNumber":21632,"sourceCode":"                validate_temperature(temp).map_err(|e| {\n                    ::zeroclaw_log::record!(\n                        WARN,\n                        ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Reject)\n                            .with_outcome(::zeroclaw_log::EventOutcome::Failure)\n                            .with_attrs(::serde_json::json!({\n                                \"profile\": profile_name,\n                                \"temperature\": temp,\n                                \"error\": format!(\"{}\", e),\n                            })),\n                        \"providers.models.<alias>.temperature rejected\"\n                    );\n                    anyhow::Error::msg(format!(\"providers.models.{profile_name}.temperature: {e}\"))\n                })?;\n            }\n\n            for (key, value) in &profile.pricing {\n                if value.is_nan() {\n                    anyhow::bail!(\n                        \"providers.models.{profile_name}.pricing.{key}: value must not be NaN\"\n                    );\n                }\n                if *value < 0.0 {\n                    anyhow::bail!(\n                        \"providers.models.{profile_name}.pricing.{key}: value must be >= 0.0 (got {value})\"\n                    );\n                }\n            }\n        }\n\n        // Non-fatal validation warnings: surfaced both via tracing (CLI sees\n        // on stderr) and via Config::collect_warnings (gateway HTTP returns\n        // structured to dashboard callers). Single source of truth lives in\n        // collect_warnings; emit each one to tracing here so the existing\n        // log behavior is preserved.\n        for w in self.collect_warnings() {\n            ::zeroclaw_log::record!(","sourceCodeStart":21614,"sourceCodeEnd":21650,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-config/src/schema.rs#L21614-L21650","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","solutions":["Replace nan with the real numeric price for the named key","If the price is genuinely unknown, use 0.0 so cost estimates read zero rather than corrupting arithmetic — or omit the key","Guard computed prices before writing config: skip or clamp values that fail is_finite()"],"exampleFix":"# before\n[providers.models.gpt-x.pricing]\ninput = nan\noutput = 0.002\n\n# after\n[providers.models.gpt-x.pricing]\ninput = 0.001\noutput = 0.002","handlingStrategy":"validation","validationCode":"fn pricing_precheck(cfg: &zeroclaw_config::Config) -> Result<(), String> {\n    for (name, profile) in &cfg.providers.models.entries {\n        for (key, value) in &profile.pricing {\n            if value.is_nan() {\n                return Err(format!(\"providers.models.{name}.pricing.{key} is NaN\"));\n            }\n        }\n    }\n    Ok(())\n}","typeGuard":"fn pricing_is_finite(pricing: &std::collections::HashMap<String, f64>) -> bool {\n    pricing.values().all(|v| v.is_finite())\n}","tryCatchPattern":"if let Err(err) = config.validate() {\n    if err.to_string().contains(\"must not be NaN\") {\n        // replace the named pricing key with a real number (0.0 if unknown) and reload\n    }\n}","preventionTips":["Never write `nan` literals in TOML pricing tables; use 0.0 for unknown prices","Run is_finite() guards in any generator that computes prices","Round-trip generated configs through TOML serialization that rejects NaN"],"tags":["configuration","validation","providers","pricing","zeroclaw","rust"],"backgroundTag":"nan-config-value","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}