{"record":{"id":"52bb400e532725aa","repo":"ScrapeGraphAI/Scrapegraph-ai","slug":"input-tokens-must-not-be-negative","errorCode":null,"errorMessage":"input_tokens must not be negative","messagePattern":"input_tokens must not be negative","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"scrapegraphai/utils/model_costs.py","lineNumber":161,"sourceCode":"                \"input\": 0.0009,\n                \"output\": 0.0036,\n                \"cache_read\": 0.00018,\n                \"cache_write\": None,\n            },\n        ),\n    }\n}\n\n\ndef get_model_cost_per_1k_tokens(\n    model_name: str,\n    input_tokens: int,\n    is_completion: bool = False,\n    service_tier: str = \"standard\",\n) -> float:\n    \"\"\"Return the applicable input or output rate for a model.\"\"\"\n    if input_tokens < 0:\n        raise ValueError(\"input_tokens must not be negative\")\n\n    if model_name in MODEL_COST_TIERS_PER_1K_TOKENS:\n        try:\n            pricing_tiers = MODEL_COST_TIERS_PER_1K_TOKENS[model_name][service_tier]\n        except KeyError as exc:\n            raise ValueError(\n                f\"Unsupported service tier {service_tier!r} for {model_name}\"\n            ) from exc\n\n        rate_key = \"output\" if is_completion else \"input\"\n        for pricing in pricing_tiers:\n            upper_bound = pricing.get(\"input_tokens_lte\")\n            lower_bound = pricing.get(\"input_tokens_gt\")\n            if upper_bound is not None and input_tokens <= upper_bound:\n                return float(pricing[rate_key])\n            if lower_bound is not None and input_tokens > lower_bound:\n                return float(pricing[rate_key])\n        raise ValueError(f\"No pricing tier matches {input_tokens} input tokens\")","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/ScrapeGraphAI/Scrapegraph-ai/blob/532dfffbf6ee823a6c9cf8cfedc24a93bf026780/scrapegraphai/utils/model_costs.py#L143-L179","documentation":"ValueError from get_model_cost_per_1k_tokens guarding against negative input_tokens. Tier selection compares input_tokens against tier bounds, so a negative count is invalid input.","triggerScenarios":"Calling get_model_cost_for_model or get_model_cost_per_1k_tokens with input_tokens < 0 (e.g. a computed prompt_tokens value that underflowed or was misparsed as negative).","commonSituations":"Callbacks parsing token usage from providers that omit prompt tokens, yielding -1 or None coerced to a negative number.","solutions":["Check the token-usage extraction: never substitute -1 for missing prompt token counts","Guard callers: max(0, input_tokens) before passing","Update the provider integration to emit 0 when usage metadata is absent"],"exampleFix":"# before\nrate = get_model_cost_per_1k_tokens(model, prompt_tokens, is_completion=True)\n# after\nrate = get_model_cost_per_1k_tokens(model, max(0, prompt_tokens), is_completion=True)","handlingStrategy":"validation","validationCode":"input_tokens = max(0, int(input_tokens or 0))\nrate = get_model_cost_per_1k_tokens(model, input_tokens, is_completion=True)","typeGuard":"def is_valid_token_count(n) -> bool:\n    return isinstance(n, int) and not isinstance(n, bool) and n >= 0","tryCatchPattern":"try:\n    rate = get_model_cost_per_1k_tokens(model, n)\nexcept ValueError as e:\n    logger.warning(\"bad token count %r: %s\", n, e)\n    rate = 0.0","preventionTips":["Never use -1 sentinels for missing token counts","Coerce usage values with int(max(0, x))","Validate provider usage metadata shape"],"tags":["validation","token-usage","cost-tracking"],"backgroundTag":"argument-validation-failed","analyzedSha":"532dfffbf6ee823a6c9cf8cfedc24a93bf026780","analyzedAt":"2026-08-28T15:19:38.821Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}