BerriAI/litellm · error · ValueError

Expected document dict, got {type(document)}

Error message

Expected document dict, got {type(document)}

What it means

Raised in transform_ocr_request when the `document` argument for Azure Document Intelligence OCR is not a dict. LiteLLM's OCR interface follows the Mistral format, where document must be a mapping like {'type': 'document_url', 'document_url': ...}; passing a bare string URL, bytes, or a pydantic object hits this check before any request is built.

Source

Thrown at litellm/llms/azure_ai/ocr/document_intelligence/transformation.py:359

        }
        OR
        {
            "base64Source": "base64_encoded_content"
        }

        Args:
            model: Model name
            document: Document dict from user (Mistral format)
            optional_params: Already mapped optional parameters
            headers: Request headers

        Returns:
            OCRRequestData with JSON data
        """
        verbose_logger.debug("Azure Document Intelligence transform_ocr_request - model: %s", model)

        if not isinstance(document, dict):
            raise ValueError(f"Expected document dict, got {type(document)}")

        # Extract document URL from Mistral format
        doc_type: Final = document.get("type")
        document_url = None

        if doc_type == "document_url":
            document_url = document.get("document_url", "")
        elif doc_type == "image_url":
            document_url = document.get("image_url", "")
        else:
            raise ValueError(f"Invalid document type: {doc_type}. Must be 'document_url' or 'image_url'")

        if not document_url:
            raise ValueError("Document URL is required")

        # Build Azure DI request
        data: Final[dict[str, Any]] = {}

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Wrap the source in a Mistral-style dict: {'type': 'document_url', 'document_url': <url>} for files, or {'type': 'image_url', 'image_url': <url or data URI>} for images.
  2. If building the dict from a pydantic model, call .model_dump() first.
  3. Check the LiteLLM OCR docs example for the exact document shape.

Example fix

# before
resp = litellm.aocr_document(model="azure_ai/doc-intelligence/prebuilt-read", document="https://x.com/f.pdf")

# after
resp = litellm.aocr_document(
    model="azure_ai/doc-intelligence/prebuilt-read",
    document={"type": "document_url", "document_url": "https://x.com/f.pdf"},
)
Defensive patterns

Strategy: type-guard

Validate before calling

def is_document_dict(v: object) -> bool:
    return isinstance(v, dict) and v.get("type") in ("document_url", "image_url") and bool(v.get("document_url") or v.get("image_url"))

Type guard

from typing import TypeIs

def is_document_dict(v: object) -> TypeIs[dict]:
    return isinstance(v, dict)

Prevention

When it happens

Trigger: Calling litellm OCR with document="https://example.com/file.pdf" (plain string), document=b'...', or a non-dict object instead of {'type': 'document_url', 'document_url': 'https://...'} or {'type': 'image_url', 'image_url': 'data:...;base64,...'}.

Common situations: Migrating from an SDK that takes a URL string directly; passing a pydantic model that wasn't dumped; forgetting the {'type': ..., url-key} wrapper when copying examples.

Related errors


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