{"record":{"id":"74e3307a56f0b6fb","repo":"BerriAI/litellm","slug":"unsupported-document-type-doc-type-expected-i","errorCode":null,"errorMessage":"Unsupported document type: {doc_type}. Expected 'image_url' or 'document_url'","messagePattern":"Unsupported document type: (.+?)\\. Expected 'image_url' or 'document_url'","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/llms/vertex_ai/ocr/deepseek_transformation.py","lineNumber":169,"sourceCode":"        Returns:\n            OCRRequestData with JSON data for the DeepSeek OCR endpoint\n        \"\"\"\n        verbose_logger.debug(\"Vertex AI DeepSeek OCR transform_ocr_request (sync) called\")\n\n        if not isinstance(document, dict):\n            raise ValueError(f\"Expected document dict, got {type(document)}\")\n\n        # Extract document type and URL\n        doc_type: Final = document.get(\"type\")\n        image_url = None\n        document_url = None\n\n        if doc_type == \"image_url\":\n            image_url = document.get(\"image_url\", \"\")\n        elif doc_type == \"document_url\":\n            document_url = document.get(\"document_url\", \"\")\n        else:\n            raise ValueError(f\"Unsupported document type: {doc_type}. Expected 'image_url' or 'document_url'\")\n\n        # Build DeepSeek OCR message content\n        content_item = {}\n        if image_url:\n            content_item = {\"type\": \"image_url\", \"image_url\": image_url}\n        elif document_url:\n            # For document URLs, we use image_url type as well (Vertex AI supports both)\n            content_item = {\"type\": \"image_url\", \"image_url\": document_url}\n\n        # Build DeepSeek OCR request\n        data: Final = {\n            \"model\": \"deepseek-ai/\" + model,\n            \"messages\": [{\"role\": \"user\", \"content\": [content_item]}],\n        }\n\n        # Add optional parameters (stream, temperature, etc.)\n        deepseek_ocr_params: Final = {}\n        for key, value in optional_params.items():","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/llms/vertex_ai/ocr/deepseek_transformation.py#L151-L187","documentation":"ValueError raised when the document dict's 'type' field is neither 'image_url' nor 'document_url'. The DeepSeek OCR transformer branches only on those two literals, so a missing 'type' key (doc_type is None) or any other spelling is rejected before a request is built.","triggerScenarios":"document={'type': 'image', ...} or {'type': 'file', ...}; the 'type' key omitted entirely so doc_type is None; values copied from another OCR vendor's schema.","commonSituations":"Schema drift between OCR providers (Mistral uses image_url/document_url while other APIs use 'image' or 'file'); unvalidated user-supplied document descriptors.","solutions":["Use exactly 'image_url' or 'document_url' as the type value","Pair it with the matching sibling key: 'image_url' for images, 'document_url' for PDFs/documents","Validate the enum before the call (see defense)"],"exampleFix":"# before\nlitellm.ocr(model='vertex_ai/deepseek-ai/deepseek-ocr', document={'type': 'image', 'url': img_url})\n\n# after\nlitellm.ocr(model='vertex_ai/deepseek-ai/deepseek-ocr', document={'type': 'image_url', 'image_url': img_url})","handlingStrategy":"validation","validationCode":"ALLOWED = ('image_url', 'document_url')\n\ndef normalize_document(doc: dict) -> dict:\n    t = doc.get('type')\n    if t == 'image':\n        doc = {**doc, 'type': 'image_url'}\n    elif t == 'file':\n        doc = {**doc, 'type': 'document_url'}\n    assert doc.get('type') in ALLOWED, f'type must be one of {ALLOWED}, got {t!r}'\n    return doc","typeGuard":"def has_supported_doc_type(doc: dict) -> bool:\n    return doc.get('type') in ('image_url', 'document_url')","tryCatchPattern":null,"preventionTips":["Map upstream document types to image_url/document_url at your API boundary","Reject documents without a recognized type early","Keep a fixture test asserting your request builder emits only the two allowed types"],"tags":["vertex-ai","ocr","request-validation","enum-value"],"backgroundTag":"invalid-request-payload","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}