BerriAI/litellm · error · ValueError

OCR response usage_info is None

Error message

OCR response usage_info is None

What it means

OCRResponse carries pricing data in its usage_info field. If the response passed to the OCR cost calculator has usage_info=None (provider returned no usage, or the transformation didn't populate it), LiteLLM refuses to compute cost and raises ValueError since pages/credits are unknown.

Source

Thrown at litellm/cost_calculator.py:1822

        model: str - model name
        custom_llm_provider: Optional[str] - custom LLM provider
        response: Optional[Any] - response object

    Returns:
        Tuple[float, float]: cost of OCR processing

        (Parent function requires a tuple, so we return a tuple. Cost is only in the first element.)
    """
    from litellm.llms.base_llm.ocr.transformation import OCRResponse

    #########################################################
    # validate it's an OCR response
    #########################################################
    if response is None or not isinstance(response, OCRResponse):
        raise ValueError(f"response must be of type OCRResponse got type={type(response)}")

    if response.usage_info is None:
        raise ValueError("OCR response usage_info is None")

    try:
        model_info: ModelInfo | None = litellm.get_model_info(model=model, custom_llm_provider=custom_llm_provider)
    except Exception:
        model_info = None

    credits: Final = getattr(response.usage_info, "credits", None)
    cost_per_credit = None
    if model_info is not None:
        cost_per_credit = model_info.get("ocr_cost_per_credit")
    if credits is not None and cost_per_credit is not None:
        return cost_per_credit * credits, 0.0

    ocr_cost_per_page: float | None = None
    if model_info is not None:
        ocr_cost_per_page = model_info.get("ocr_cost_per_page")

    pages_processed: Final = response.usage_info.pages_processed

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Populate usage_info when building OCRResponse (pages_processed and/or credits).
  2. Fix the provider transformation to map the provider's usage fields into OCRUsageInfo.
  3. Retry/bill externally when the provider genuinely returns no usage data rather than forcing cost calc.
  4. Update LiteLLM for transformation fixes if the provider does return usage.

Example fix

# before
ocr = OCRResponse(id=..., text=...)  # usage_info omitted -> None

# after
from litellm.llms.base_llm.ocr.transformation import OCRUsageInfo
ocr = OCRResponse(id=..., text=..., usage_info=OCRUsageInfo(pages_processed=2))
Defensive patterns

Strategy: type-guard

Validate before calling

if response.usage_info is None:
    raise ValueError("OCR response missing usage_info; cannot price")

Type guard

def ocr_usage_present(resp) -> bool:
    return isinstance(resp, OCRResponse) and resp.usage_info is not None

Try / catch

try:
    cost = ocr_cost_fn(response=resp, model=model)
except ValueError as e:
    if "usage_info is None" in str(e):
        cost = 0.0  # bill externally; log the gap
    else:
        raise

Prevention

When it happens

Trigger: Constructing OCRResponse without usage_info; an OCR provider call whose response lacks usage metadata; a transformation that maps usage fields only conditionally.

Common situations: Custom OCR integrations that skip usage mapping; providers that don't report pages processed; partially-implemented OCR transformations after upgrading LiteLLM.

Related errors


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