BerriAI/litellm · error · NotImplementedError
transform_ocr_response must be implemented by provider
Error message
transform_ocr_response must be implemented by provider
What it means
Base OCR transformation stub for transform_ocr_response: mapping a provider's raw httpx.Response to the standard OCRResponse is provider-specific, so the base class raises NotImplementedError. Seeing it means the request may have even succeeded at HTTP level but no response parser was wired in the active config.
Source
Thrown at litellm/llms/base_llm/ocr/transformation.py:222
model=model,
document=document,
optional_params=optional_params,
headers=headers,
**kwargs,
)
def transform_ocr_response(
self,
model: str,
raw_response: httpx.Response,
logging_obj: LiteLLMLoggingObj,
**kwargs,
) -> OCRResponse:
"""
Transform provider-specific OCR response to standard format.
Override in provider-specific implementations.
"""
raise NotImplementedError("transform_ocr_response must be implemented by provider")
async def async_transform_ocr_response(
self,
model: str,
raw_response: httpx.Response,
logging_obj: LiteLLMLoggingObj,
**kwargs,
) -> OCRResponse:
"""
Async transform provider-specific OCR response to standard format.
Optional method - providers can override if they need async transformations
(e.g., Azure Document Intelligence for async operation polling).
Default implementation falls back to sync transform_ocr_response.
Args:
model: Model name
raw_response: Raw HTTP responseView on GitHub (pinned to 6c2dcb801b)
Solutions
- Implement transform_ocr_response in the config to build OCRResponse from the provider JSON.
- If only the async variant is implemented, route calls through the async path (async_transform_ocr_response).
- Verify the model's provider resolves to the intended config class.
- Use a built-in OCR provider with full response support.
Example fix
# before: no response transform
class MyOCRConfig(BaseOCRConfig): ...
# after
class MyOCRConfig(BaseOCRConfig):
def transform_ocr_response(self, model, raw_response, logging_obj, **kwargs):
body = raw_response.json()
return OCRResponse(text=body['content'], model=model, source='ocr') Defensive patterns
Strategy: type-guard
Type guard
def can_transform_ocr_response(config) -> bool:
base = BaseOCRConfig
return (type(config).transform_ocr_response is not base.transform_ocr_response
or type(config).async_transform_ocr_response is not base.async_transform_ocr_response) Try / catch
try:
ocr_resp = config.transform_ocr_response(model, raw_response, logging_obj)
except NotImplementedError:
ocr_resp = await config.async_transform_ocr_response(model, raw_response, logging_obj) # async-only config Prevention
- Implement both sync and async response hooks, or clearly support only one and route accordingly.
- Test the full OCR round trip per provider, not just request building.
- Fail registration if a config implements request but not response transforms.
When it happens
Trigger: A provider config without transform_ocr_response reached the response-handling stage of an OCR call; async providers overriding only async_transform_ocr_response but invoked on a sync path (or vice versa); base config selected via misrouted provider name.
Common situations: Custom OCR integrations that stop at request building; sync/async method mismatches; version skew between litellm core and provider configs.
Related errors
- get_complete_url must be implemented by provider
- transform_ocr_request must be implemented by provider
- ImageVariationConfig implements 'transform_response_image_va
- ImageVariationConfig implements 'transform_response_image_va
- Unclassified keys in {PRICES_PATH.name}: {', '.join(unclassi
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/3f6abd27668f9643.
Report an issue: GitHub.