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

  1. Wrap the URL: document={'type': 'document_url', 'document_url': 'https://example.com/doc.pdf'}
  2. If you have a JSON string, parse it first: document=json.loads(payload)
  3. 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

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


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