{"record":{"id":"f39c69652e84503f","repo":"BerriAI/litellm","slug":"model-is-none-and-does-not-exist-in-passed-complet","errorCode":null,"errorMessage":"Model is None and does not exist in passed completion_response. Passed completion_response={completion_response}, model={model}","messagePattern":"Model is None and does not exist in passed completion_response\\. Passed completion_response=(.+?), model=(.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/cost_calculator.py","lineNumber":1307,"sourceCode":"                    total_time = getattr(completion_response, \"_response_ms\", 0)\n\n                    hidden_params = getattr(completion_response, \"_hidden_params\", None)\n                    if hidden_params is not None:\n                        custom_llm_provider = hidden_params.get(\"custom_llm_provider\", custom_llm_provider or None)\n                        region_name = hidden_params.get(\"region_name\", region_name)\n\n                        # For Gemini/Vertex AI responses, trafficType is stored in\n                        # provider_specific_fields.  Map it to the service_tier used\n                        # by the cost key lookup (_priority / _flex suffixes) so that\n                        # ON_DEMAND_PRIORITY requests are billed at priority prices.\n                        if service_tier is None:\n                            provider_specific = hidden_params.get(\"provider_specific_fields\") or {}\n                            raw_traffic_type = provider_specific.get(\"traffic_type\")\n                            if raw_traffic_type:\n                                service_tier = _map_traffic_type_to_service_tier(raw_traffic_type)\n                else:\n                    if model is None:\n                        raise ValueError(\n                            f\"Model is None and does not exist in passed completion_response. Passed completion_response={completion_response}, model={model}\"\n                        )\n                    if len(messages) > 0:\n                        prompt_tokens = token_counter(model=model, messages=messages)\n                    elif len(prompt) > 0:\n                        prompt_tokens = token_counter(model=model, text=prompt)\n                    completion_tokens = token_counter(model=model, text=completion)\n\n                # Handle A2A calls before model check - A2A doesn't require a model\n                if call_type in _A2A_CALL_TYPES:\n                    from litellm.a2a_protocol.cost_calculator import A2ACostCalculator\n\n                    return A2ACostCalculator.calculate_a2a_cost(litellm_logging_obj=litellm_logging_obj)\n\n                if model is None:\n                    raise ValueError(\n                        f\"Model is None and does not exist in passed completion_response. Passed completion_response={completion_response}, model={model}\"\n                    )","sourceCodeStart":1289,"sourceCodeEnd":1325,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/cost_calculator.py#L1289-L1325","documentation":"In completion_cost's no-usage branch, LiteLLM falls back to counting tokens locally with token_counter, which needs a model name. If the completion_response carries neither usage nor a model, and the caller passed model=None, it cannot even estimate tokens and raises ValueError echoing the response object.","triggerScenarios":"completion_cost(completion_response=resp) where resp has no 'usage' and no 'model' field and no model argument was supplied; common with hand-built ModelResponse objects in tests or post-processed responses.","commonSituations":"Mocked/stub responses in unit tests; response objects serialized through a layer that drops fields; custom providers whose transformations don't populate model or usage.","solutions":["Pass model explicitly: completion_cost(completion_response=resp, model='gpt-4o').","Set usage on the response (resp['usage'] = Usage(prompt_tokens=..., completion_tokens=...)) so the local-count fallback is skipped.","Ensure custom provider transformations populate ModelResponse.model and usage.","In tests, clone a recorded real response rather than constructing an empty ModelResponse."],"exampleFix":"# before\nresp = ModelResponse(choices=[...])  # no model, no usage\ncost = litellm.completion_cost(completion_response=resp)\n\n# after\nresp = ModelResponse(choices=[...], model=\"gpt-4o-mini\")\ncost = litellm.completion_cost(completion_response=resp, model=\"gpt-4o-mini\")","handlingStrategy":"validation","validationCode":"if not completion_response.get(\"usage\") and model is None:\n    model = completion_response.get(\"model\") or request_model\n    if model is None:\n        raise ValueError(\"response has neither usage nor model; cannot count tokens\")","typeGuard":"def cost_countable(resp, model: str | None) -> bool:\n    return bool(resp.get(\"usage\")) or model is not None or bool(resp.get(\"model\"))","tryCatchPattern":"try:\n    cost = litellm.completion_cost(completion_response=resp, model=model)\nexcept ValueError as e:\n    if \"Model is None\" in str(e):\n        cost = None  # skip billing for this response; alert\n    else:\n        raise","preventionTips":["Thread the request model into every cost calculation call.","Populate usage on responses in tests: resp['usage'] = Usage(prompt_tokens=10, completion_tokens=5).","Alert on skipped cost calculations rather than silently dropping them."],"tags":["litellm","cost-calculation","model-name","usage"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}