BerriAI/litellm · error · ValueError

Either a chat completion object or the text response needs t

Error message

Either a chat completion object or the text response needs to be passed in. Learn more - https://docs.litellm.ai/docs/budget_manager

What it means

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.

Source

Thrown at litellm/budget_manager.py:137

        output_text: str | None = None,
    ):
        if model and input_text and output_text:
            prompt_tokens = litellm.token_counter(model=model, messages=[{"role": "user", "content": input_text}])
            completion_tokens = litellm.token_counter(model=model, messages=[{"role": "user", "content": output_text}])
            (
                prompt_tokens_cost_usd_dollar,
                completion_tokens_cost_usd_dollar,
            ) = litellm.cost_per_token(
                model=model,
                prompt_tokens=prompt_tokens,
                completion_tokens=completion_tokens,
            )
            cost = prompt_tokens_cost_usd_dollar + completion_tokens_cost_usd_dollar
        elif completion_obj:
            cost = litellm.completion_cost(completion_response=completion_obj)
            model = completion_obj["model"]  # if this throws an error try, model = completion_obj['model']
        else:
            raise ValueError(
                "Either a chat completion object or the text response needs to be passed in. Learn more - https://docs.litellm.ai/docs/budget_manager"
            )

        self.user_dict[user]["current_cost"] = cost + self.user_dict[user].get("current_cost", 0)
        if "model_cost" in self.user_dict[user]:
            self.user_dict[user]["model_cost"][model] = cost + self.user_dict[user]["model_cost"].get(model, 0)
        else:
            self.user_dict[user]["model_cost"] = {model: cost}

        self._save_data_thread()  # [Non-Blocking] Update persistent storage without blocking execution
        return {"user": self.user_dict[user]}

    def get_current_cost(self, user):
        return self.user_dict[user].get("current_cost", 0)

    def get_model_cost(self, user):
        return self.user_dict[user].get("model_cost", 0)

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Pass the full completion response: budget_manager.update_cost(user=user, completion_obj=response) so completion_cost can read model and usage.
  2. Or pass model plus the raw prompt text/messages so token counting can run.
  3. For streaming, accumulate the response first (or use the proxy's spend-tracking which handles this).

Example fix

# before
budget_manager.update_cost(user=user, model="gpt-4o", messages=[])

# after
budget_manager.update_cost(user=user, completion_obj=response)
# or: budget_manager.update_cost(user=user, model="gpt-4o", messages=[{"role": "user", "content": "hi"}])
Defensive patterns

Strategy: validation

Validate before calling

if completion_obj is None and not (model and messages):
    raise ValueError("update_cost needs a completion object or model+messages")

Type guard

def is_usable_completion(obj) -> bool:
    return isinstance(obj, dict) and "model" in obj and "usage" in obj

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15). Data as JSON: /api/errors/d0b7fb28a6ef9134. Report an issue: GitHub.