BerriAI/litellm · error · ValueError
Expected document dict, got {type(document)}
Error message
Expected document dict, got {type(document)} What it means
Raised by litellm's Mistral OCR transformer in transform_ocr_request when the `document` argument is not a Python dict. Mistral's native OCR API expects a document object (e.g. {"type": "document_url", "document_url": ...} or image_url variant), and litellm passes the user-supplied document through verbatim, so it must already be a dict in Mistral format.
Source
Thrown at litellm/llms/mistral/ocr/transformation.py:183
"include_image_base64": false, # optional
...
}
Args:
model: Model name (e.g., "mistral-ocr-latest")
document: Document dict from user (Mistral format) - already validated in main.py
optional_params: Already mapped optional parameters
headers: Request headers
Returns:
OCRRequestData with JSON data
"""
verbose_logger.debug("Mistral OCR transform_ocr_request - model: %s", model)
# Document parameter is the Mistral-format dict from the user
# Just pass it through as-is to the Mistral API
if not isinstance(document, dict):
raise ValueError(f"Expected document dict, got {type(document)}")
# Build request data - use document dict directly
data: Final = {
"model": model,
"document": document, # Pass through the Mistral-format document dict
}
# Add all optional parameters from the already-mapped optional_params
data.update(optional_params)
# No multipart files - using JSON
return OCRRequestData(data=data, files=None)
def transform_ocr_response(
self,
model: str,
raw_response: httpx.Response,
logging_obj: Any,View on GitHub (pinned to 6c2dcb801b)
Solutions
- Pass document as a Mistral-format dict: {"type": "document_url", "document_url": "https://..."} for PDFs or {"type": "image_url", "image_url": "https://..."} for images.
- If you built a Pydantic/dataclass object, call .model_dump() / .dict() first.
- Never pass a raw URL string or file path as document for mistral models.
Example fix
# before
litellm.ocr(model="mistral/mistral-ocr-latest", document="https://x.com/a.pdf")
# after
litellm.ocr(
model="mistral/mistral-ocr-latest",
document={"type": "document_url", "document_url": "https://x.com/a.pdf"},
) Defensive patterns
Strategy: type-guard
Validate before calling
def is_mistral_document(doc: object) -> bool:
return isinstance(doc, dict) and doc.get("type") in {"document_url", "image_url"} and (
"document_url" in doc or "image_url" in doc
) Type guard
from typing import Any, TypeGuard
def is_mistral_ocr_document(value: Any) -> TypeGuard[dict]:
return (
isinstance(value, dict)
and isinstance(value.get("type"), str)
and any(k in value for k in ("document_url", "image_url"))
) Try / catch
try:
litellm.ocr(model="mistral/mistral-ocr-latest", document=doc)
except ValueError as e:
if "Expected document dict" in str(e):
raise TypeError("document must be a Mistral-format dict") from e
raise Prevention
- Construct the document dict at the edge of your API, not inline at call sites.
- Serialize Pydantic models with .model_dump() before passing.
- Never pass a bare URL string as document for mistral OCR.
When it happens
Trigger: Calling litellm.ocr(model='mistral/mistral-ocr-latest', document=<string or object>) — e.g. passing a bare URL string, a Pydantic model, or a file path instead of the Mistral-format dict.
Common situations: Developers coming from other OCR APIs that accept a URL string directly, or passing an unserialized object; also passing document as bytes.
Related errors
- response must be of type OCRResponse got type={type(response
- `pages` must be integers, not booleans
- `pages` must be a list[int] (0-based, Mistral-style) or a st
- Expected document dict, got {type(document)}
- Invalid document type: {doc_type}. Must be 'document_url' or
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/4583264bc35a8756.
Report an issue: GitHub.