{"record":{"id":"d0b7fb28a6ef9134","repo":"BerriAI/litellm","slug":"either-a-chat-completion-object-or-the-text-respon","errorCode":null,"errorMessage":"Either a chat completion object or the text response needs to be passed in. Learn more - https://docs.litellm.ai/docs/budget_manager","messagePattern":"Either a chat completion object or the text response needs to be passed in\\. Learn more - https://docs\\.litellm\\.ai/docs/budget_manager","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/budget_manager.py","lineNumber":137,"sourceCode":"        output_text: str | None = None,\n    ):\n        if model and input_text and output_text:\n            prompt_tokens = litellm.token_counter(model=model, messages=[{\"role\": \"user\", \"content\": input_text}])\n            completion_tokens = litellm.token_counter(model=model, messages=[{\"role\": \"user\", \"content\": output_text}])\n            (\n                prompt_tokens_cost_usd_dollar,\n                completion_tokens_cost_usd_dollar,\n            ) = litellm.cost_per_token(\n                model=model,\n                prompt_tokens=prompt_tokens,\n                completion_tokens=completion_tokens,\n            )\n            cost = prompt_tokens_cost_usd_dollar + completion_tokens_cost_usd_dollar\n        elif completion_obj:\n            cost = litellm.completion_cost(completion_response=completion_obj)\n            model = completion_obj[\"model\"]  # if this throws an error try, model = completion_obj['model']\n        else:\n            raise ValueError(\n                \"Either a chat completion object or the text response needs to be passed in. Learn more - https://docs.litellm.ai/docs/budget_manager\"\n            )\n\n        self.user_dict[user][\"current_cost\"] = cost + self.user_dict[user].get(\"current_cost\", 0)\n        if \"model_cost\" in self.user_dict[user]:\n            self.user_dict[user][\"model_cost\"][model] = cost + self.user_dict[user][\"model_cost\"].get(model, 0)\n        else:\n            self.user_dict[user][\"model_cost\"] = {model: cost}\n\n        self._save_data_thread()  # [Non-Blocking] Update persistent storage without blocking execution\n        return {\"user\": self.user_dict[user]}\n\n    def get_current_cost(self, user):\n        return self.user_dict[user].get(\"current_cost\", 0)\n\n    def get_model_cost(self, user):\n        return self.user_dict[user].get(\"model_cost\", 0)\n","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/budget_manager.py#L119-L155","documentation":"ValueError from BudgetManager.update_cost: cost could not be computed because neither the inputs needed for token-based costing (text/messages with a model) nor a chat completion object was supplied. The method computes cost either via litellm.completion_cost(completion_response=...) when a completion object is given, or via token counting when raw text/messages plus model are given; with neither path satisfiable it raises.","triggerScenarios":"Calling budget_manager.update_cost(user='u', ...) without a completion_obj and without a usable (model, messages/text) pair — e.g. passing only kwargs like custom_pricing_entry but no response, or an empty messages list so both branches fall through to the else.","commonSituations":"Custom hook code calling update_cost at the wrong lifecycle point (before the response exists); passing a streaming chunk or an object without model/usage keys; refactoring that drops the completion argument.","solutions":["Pass the full completion response: budget_manager.update_cost(user=user, completion_obj=response) so completion_cost can read model and usage.","Or pass model plus the raw prompt text/messages so token counting can run.","For streaming, accumulate the response first (or use the proxy's spend-tracking which handles this)."],"exampleFix":"# before\nbudget_manager.update_cost(user=user, model=\"gpt-4o\", messages=[])\n\n# after\nbudget_manager.update_cost(user=user, completion_obj=response)\n# or: budget_manager.update_cost(user=user, model=\"gpt-4o\", messages=[{\"role\": \"user\", \"content\": \"hi\"}])","handlingStrategy":"validation","validationCode":"if completion_obj is None and not (model and messages):\n    raise ValueError(\"update_cost needs a completion object or model+messages\")","typeGuard":"def is_usable_completion(obj) -> bool:\n    return isinstance(obj, dict) and \"model\" in obj and \"usage\" in obj","tryCatchPattern":null,"preventionTips":["Call update_cost only after a completed, non-streaming response is in hand.","For streaming, use LiteLLM's built-in success callbacks for spend tracking instead of manual update_cost.","Assert response shape (model, usage keys) before passing to update_cost."],"tags":["budget-manager","cost-tracking","validation","python"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}