{"record":{"id":"4b0dfc97d4152411","repo":"zeroclaw-labs/zeroclaw","slug":"providers-models-profile-name-pricing-key-val-4b0dfc","errorCode":null,"errorMessage":"providers.models.{profile_name}.pricing.{key}: value must be >= 0.0 (got {value})","messagePattern":"providers\\.models\\.(.+?)\\.pricing\\.(.+?): value must be >= 0\\.0 \\(got (.+?)\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-config/src/schema.rs","lineNumber":21637,"sourceCode":"                            .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!(\n                WARN,\n                ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Note)\n                    .with_outcome(::zeroclaw_log::EventOutcome::Unknown)\n                    .with_attrs(::serde_json::json!({\"path\": w.path, \"code\": w.code})),\n                &format!(\"{}\", w.message)","sourceCodeStart":21619,"sourceCodeEnd":21655,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-config/src/schema.rs#L21619-L21655","documentation":"In the same pricing-map loop as the NaN check, any value < 0.0 bails with the key and value printed. Negative prices corrupt cost accounting (they produce negative invoices) and almost always indicate a unit or sign mistake rather than intent. Both checks run per key, so a map with several bad values reports the first one.","triggerScenarios":"Set any pricing key to a negative number, e.g. `input = -0.001`, or generate pricing from arithmetic that underflows to a tiny negative value (per-1M to per-token conversion bugs).","commonSituations":"Transcribing vendor pricing sheets where credits/discounts are negative; spreadsheet copy-paste carrying minus signs; float arithmetic like `x/1000 - epsilon` producing -1e-19.","solutions":["Correct the sign of the named key","Check unit scale: many vendors quote $/1M tokens — convert to the per-token figure the config expects before storing","Clamp generated prices at 0.0 (pricing config generators should emit `v.max(0.0)`)","Re-run validation to catch remaining keys — only the first failing key is reported per run"],"exampleFix":"# before\n[providers.models.gpt-x.pricing]\ninput = -0.001\noutput = 0.002\n\n# after\n[providers.models.gpt-x.pricing]\ninput = 0.001\noutput = 0.002","handlingStrategy":"validation","validationCode":"fn pricing_nonneg_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 < 0.0 {\n                return Err(format!(\"providers.models.{name}.pricing.{key} = {value} < 0\"));\n            }\n        }\n    }\n    Ok(())\n}","typeGuard":"fn pricing_is_nonnegative(pricing: &std::collections::HashMap<String, f64>) -> bool {\n    pricing.values().all(|v| *v >= 0.0)\n}","tryCatchPattern":"if let Err(err) = config.validate() {\n    if err.to_string().contains(\"must be >= 0.0\") {\n        // fix the sign/unit of the named key (check $/1M vs per-token scale) and reload\n    }\n}","preventionTips":["Convert vendor $/1M-token quotes to per-token before storing","Clamp computed prices with v.max(0.0) in generators","Review spreadsheet-copied values for stray minus signs"],"tags":["configuration","validation","providers","pricing","zeroclaw","rust"],"backgroundTag":"negative-config-value","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}