BerriAI/litellm · error · ValueError
OCR response pages_processed is None
Error message
OCR response pages_processed is None
What it means
For per-page OCR pricing, usage_info.pages_processed must be set. If credits-based pricing didn't apply (no credits or no ocr_cost_per_credit) and pages_processed is None, the calculator raises ValueError rather than silently returning zero cost — missing usage is surfaced as an error except in the credit-model case, which logs a warning and returns 0.0.
Source
Thrown at litellm/cost_calculator.py:1855
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
if pages_processed is None:
if cost_per_credit is not None or ocr_cost_per_page is None:
# Surface missing usage data instead of silently under-reporting
# cost. The previous behavior raised ValueError; we now return 0.0
# for credit-priced or unpriced models, so log a warning to keep
# the regression visible to operators.
verbose_logger.warning(
"OCR cost: model=%s custom_llm_provider=%s response.usage_info."
"pages_processed is None and credits=%s; returning 0.0 cost.",
model,
custom_llm_provider,
credits,
)
return 0.0, 0.0
raise ValueError("OCR response pages_processed is None")
if ocr_cost_per_page is None:
# No per-page pricing configured. Either the model is on credit-based
# pricing (and credits weren't returned, so the credit branch above did
# not match) or the model has no OCR pricing entry at all. Surface a
# warning so that missing pricing entries are visible rather than
# silently producing zero cost for billable usage.
verbose_logger.warning(
"OCR cost: model=%s custom_llm_provider=%s reported "
"pages_processed=%s but no ocr_cost_per_page is configured; "
"returning 0.0 cost.",
model,
custom_llm_provider,
pages_processed,
)
return 0.0, 0.0
total_ocr_processing_cost: Final[float] = ocr_cost_per_page * pages_processedView on GitHub (pinned to 6c2dcb801b)
Solutions
- Map pages_processed in your OCR transformation whenever the provider reports it.
- Align the model's pricing entry: either supply usage pages for ocr_cost_per_page models or add ocr_cost_per_credit for credit-priced models.
- If the provider returns only credits, register ocr_cost_per_credit via litellm.register_model so the credit branch handles it.
- Treat missing usage as a provider bug — capture the raw response to confirm what it reports.
Example fix
# before
usage = OCRUsageInfo(credits=None) # pages_processed omitted
# after
usage = OCRUsageInfo(pages_processed=provider_resp["pages"], credits=provider_resp.get("credits")) Defensive patterns
Strategy: validation
Validate before calling
info = litellm.get_model_info(model=model, custom_llm_provider=custom_llm_provider) or {}
per_page = info.get("ocr_cost_per_page")
per_credit = info.get("ocr_cost_per_credit")
credits = getattr(response.usage_info, "credits", None) if response.usage_info else None
pages = getattr(response.usage_info, "pages_processed", None) if response.usage_info else None
if pages is None and not (credits is not None and per_credit is not None):
raise MissingOcrUsage(model) Type guard
def ocr_priceable(resp, model: str) -> bool:
ui = getattr(resp, "usage_info", None)
if ui is None:
return False
if getattr(ui, "pages_processed", None) is not None:
return True
return getattr(ui, "credits", None) is not None Try / catch
try:
cost = ocr_cost_fn(response=resp, model=model)
except ValueError as e:
if "pages_processed is None" in str(e):
log_underreported_ocr(model)
cost = 0.0
else:
raise Prevention
- Ensure the OCR transformation always maps pages_processed when the provider reports it.
- Match the usage fields you populate to the model's pricing keys (per-page vs per-credit).
- Alert when OCR usage comes back empty so costs are never silently zero.
When it happens
Trigger: OCRResponse with usage_info present but pages_processed=None and no usable credits; calling the OCR cost calculator on a response whose usage only carries credits while the model is priced per page (no ocr_cost_per_credit in model_info).
Common situations: Mixed pricing models (credit-based provider, per-page model entry); transformations that map credits but not page counts; new OCR models whose usage schema differs.
Related errors
- OCR response usage_info is None
- cost for tts call is None. prompt_cost={_prompt_cost}, compl
- Model is None and does not exist in passed completion_respon
- usage object and custom_llm_provider must be provided for re
- response must be of type OCRResponse got type={type(response
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/887d2827734f573c.
Report an issue: GitHub.