{"record":{"id":"d9c6cec4e2e675b3","repo":"zeroclaw-labs/zeroclaw","slug":"token-usage-cost-must-be-a-finite-non-negative-va","errorCode":null,"errorMessage":"Token usage cost must be a finite, non-negative value","messagePattern":"Token usage cost must be a finite, non-negative value","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-config/src/cost/tracker.rs","lineNumber":236,"sourceCode":"        honor_enabled: bool,\n    ) -> Result<()> {\n        let (enabled, track_per_agent) = {\n            let config = self.config.read();\n            (config.enabled, config.track_per_agent)\n        };\n        if honor_enabled && !enabled {\n            return Ok(());\n        }\n\n        if !usage.cost_usd.is_finite() || usage.cost_usd < 0.0 {\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!({\"cost_usd\": usage.cost_usd})),\n                \"token usage record rejected: cost is not finite or is negative\"\n            );\n            anyhow::bail!(\"Token usage cost must be a finite, non-negative value\");\n        }\n\n        let effective_alias = if track_per_agent {\n            agent_alias.map(str::to_string)\n        } else {\n            None\n        };\n        let cost_usd = usage.cost_usd;\n        let total_tokens = usage.total_tokens;\n        let record =\n            CostRecord::with_attribution(&self.session_id, effective_alias.clone(), task_id, usage);\n\n        {\n            let mut storage = self.lock_storage();\n            storage.add_record(record)?;\n        }\n\n        {","sourceCodeStart":218,"sourceCodeEnd":254,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-config/src/cost/tracker.rs#L218-L254","documentation":"The internal recorder behind record_usage_with_owned_task_attribution and record_scoped_usage_with_owned_task_attribution validates that usage.cost_usd is finite and non-negative before writing it into aggregated storage. This mirrors the check_budget guard: a single NaN or negative cost would corrupt daily/monthly aggregates and every later limit decision. Rejections are logged as WARN Reject events with the cost_usd attribute attached.","triggerScenarios":"Calling record_usage_with_owned_task_attribution (or the scoped variant) with a UsageRecord whose cost_usd field is NaN, infinite, or negative — typically because the cost was computed from a missing price entry or a bad parse upstream.","commonSituations":"Provider pricing lookups that return Option::None and get unwisely mapped to NaN; per-token cost arithmetic hitting infinity on zero-division; discount/refund logic subtracting past zero before recording usage.","solutions":["Fix the upstream cost computation so cost_usd is always a finite >= 0.0 value","Treat a missing price as 0.0 and log it, rather than propagating NaN into the record","Sanitize the record before submission: `let cost = if usage.cost_usd.is_finite() && usage.cost_usd >= 0.0 { usage.cost_usd } else { 0.0 };`","Add tests over the pricing table for every model name you actually route to"],"exampleFix":"// before\ntracker.record_usage_with_owned_task_attribution(usage, task_id).await?;\n\n// after\nlet mut usage = usage;\nif !usage.cost_usd.is_finite() || usage.cost_usd < 0.0 {\n    usage.cost_usd = 0.0;\n}\ntracker.record_usage_with_owned_task_attribution(usage, task_id).await?;","handlingStrategy":"validation","validationCode":"let mut record = record;\nif !record.cost_usd.is_finite() || record.cost_usd < 0.0 {\n    tracing::warn!(cost = record.cost_usd, \"invalid cost; recording as 0.0\");\n    record.cost_usd = 0.0;\n}\ntracker.record_usage_with_owned_task_attribution(record, task_id).await?;","typeGuard":"fn has_valid_cost(u: &UsageRecord) -> bool {\n    u.cost_usd.is_finite() && u.cost_usd >= 0.0\n}","tryCatchPattern":"if let Err(e) = tracker.record_usage_with_owned_task_attribution(record.clone(), task_id).await {\n    if !record.cost_usd.is_finite() || record.cost_usd < 0.0 {\n        tracing::error!(error = %e, \"usage cost invalid; dropping record to protect aggregates\");\n        return Ok(());\n    }\n    return Err(e);\n}","preventionTips":["Compute cost in one place that clamps to finite non-negative before building the record","Log the raw price inputs whenever a record is rejected so the pricing bug is findable","Fuzz the pricing lookup with unknown model names in tests"],"tags":["cost-tracking","usage","nan","floating-point","validation"],"backgroundTag":"nan-float-value-rejected","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}