BerriAI/litellm · error · ValueError
Expected document dict, got {type(document)}
Error message
Expected document dict, got {type(document)} What it means
The sync OCR request transformer requires the document argument to be a Python dict (LiteLLM's document format, e.g. {'type': 'document_url', 'document_url': ...}). If you pass anything else — a string URL, a JSON string, a pydantic object — this ValueError fires before any network call.
Source
Thrown at litellm/llms/azure_ai/ocr/transformation.py:182
Transform OCR request for Azure AI, converting URLs to base64 data URIs (sync).
Azure AI OCR doesn't have internet access, so we automatically fetch
any URLs and convert them to base64 data URIs synchronously.
Args:
model: Model name
document: Document dict from user
optional_params: Already mapped optional parameters
headers: Request headers
**kwargs: Additional arguments
Returns:
OCRRequestData with JSON data
"""
verbose_logger.debug("Azure AI OCR transform_ocr_request (sync) - model: %s", model)
if not isinstance(document, dict):
raise ValueError(f"Expected document dict, got {type(document)}")
# Check if we need to convert URL to base64
doc_type: Final = document.get("type")
transformed_document: Final = document.copy()
if doc_type == "document_url":
document_url: Final = document.get("document_url", "")
# If it's not already a data URI, convert it
if document_url and not document_url.startswith("data:"):
verbose_logger.debug("Azure AI OCR: Converting document URL to base64 data URI (sync)")
data_uri = self._convert_url_to_data_uri_sync(url=document_url)
transformed_document["document_url"] = data_uri
elif doc_type == "image_url":
image_url: Final = document.get("image_url", "")
# If it's not already a data URI, convert it
if image_url and not image_url.startswith("data:"):
verbose_logger.debug("Azure AI OCR: Converting image URL to base64 data URI (sync)")
data_uri = self._convert_url_to_data_uri_sync(url=image_url)View on GitHub (pinned to 6c2dcb801b)
Solutions
- Wrap the URL: document={'type': 'document_url', 'document_url': 'https://example.com/doc.pdf'}
- If you have a JSON string, parse it first: document=json.loads(payload)
- For base64 input use {'type': 'document_url', 'document_url': 'data:application/pdf;base64,...'} or the image variant {'type': 'image_url', 'image_url': ...}
Example fix
# before
result = litellm.ocr(model='azure_ai/mistral-ocr', document='https://example.com/invoice.pdf')
# after
result = litellm.ocr(model='azure_ai/mistral-ocr', document={'type': 'document_url', 'document_url': 'https://example.com/invoice.pdf'}) Defensive patterns
Strategy: type-guard
Validate before calling
def to_ocr_document(value) -> dict:
if not isinstance(value, dict):
raise TypeError('document must be a dict like {"type": "document_url", "document_url": ...}')
return value Type guard
def is_ocr_document(value) -> bool:
return isinstance(value, dict) and isinstance(value.get('type'), str) Try / catch
try:
litellm.ocr(model='azure_ai/mistral-ocr', document=doc)
except ValueError as e:
if 'Expected document dict' in str(e):
doc = {'type': 'document_url', 'document_url': str(doc)}
else:
raise Prevention
- Always build the document dict through one helper function instead of inline literals
- Parse JSON strings at the system boundary, never inside the LLM call
When it happens
Trigger: Calling litellm.ocr(model=..., document='https://example.com/doc.pdf') instead of wrapping the URL in a dict; passing a JSON-encoded string like json.dumps({...}); passing an object with attributes instead of a plain dict.
Common situations: Porting code from the raw Mistral OCR API that takes a URL string; forgetting the required 'type' envelope after reading docs quickly; data flowing from another service as a string payload.
Related errors
- max retries must be an int
- Invalid `pages` string for Azure Document Intelligence: {pag
- `pages` integers must be >= 0 (Mistral 0-based indices)
- Invalid `pages` list for Azure Document Intelligence: {pages
- Expected document dict, got {type(document)}
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/0d8ee9d2a90e33e7.
Report an issue: GitHub.