{"record":{"id":"0e86fac210740ae3","repo":"BerriAI/litellm","slug":"file-id-or-file-data-is-required","errorCode":null,"errorMessage":"file_id or file_data is required","messagePattern":"file_id or file_data is required","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/llms/hosted_vllm/chat/transformation.py","lineNumber":146,"sourceCode":"            mime_type = _parse_mime_type(file_data)\n            if mime_type and mime_type.startswith(\"video/\"):\n                return True\n        elif file_id:\n            mime_type = _get_image_mime_type_from_url(file_id)\n            if mime_type and mime_type.startswith(\"video/\"):\n                return True\n        return False\n\n    def _convert_file_to_video_url(self, content_item: ChatCompletionFileObject) -> ChatCompletionVideoObject:\n        file: Final = content_item.get(\"file\", {})\n        file_id: Final = file.get(\"file_id\")\n        file_data: Final = file.get(\"file_data\")\n\n        if file_id:\n            return ChatCompletionVideoObject(type=\"video_url\", video_url=ChatCompletionVideoUrlObject(url=file_id))\n        elif file_data:\n            return ChatCompletionVideoObject(type=\"video_url\", video_url=ChatCompletionVideoUrlObject(url=file_data))\n        raise ValueError(\"file_id or file_data is required\")\n\n    @overload\n    def _transform_messages(\n        self, messages: list[AllMessageValues], model: str, is_async: Literal[True]\n    ) -> Coroutine[Any, Any, list[AllMessageValues]]: ...\n\n    @overload\n    def _transform_messages(\n        self,\n        messages: list[AllMessageValues],\n        model: str,\n        is_async: Literal[False] = False,\n    ) -> list[AllMessageValues]: ...\n\n    def _transform_messages(\n        self, messages: list[AllMessageValues], model: str, is_async: bool = False\n    ) -> list[AllMessageValues] | Coroutine[Any, Any, list[AllMessageValues]]:\n        \"\"\"","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/llms/hosted_vllm/chat/transformation.py#L128-L164","documentation":"When transforming chat messages for hosted vLLM, a message part of type 'file' is converted into a 'video_url' part by _convert_file_to_video_url(). The nested file object must contain either file_id (used directly as the video URL) or file_data (base64/data payload used as the URL). If both are missing or empty, a ValueError is raised during request transformation, before any HTTP call.","triggerScenarios":"Sending a message like {'role':'user','content':[{'type':'file','file':{}}]} or {'type':'file','file':{'filename':'clip.mp4'}} (keys other than file_id/file_data) to a hosted_vllm model. The raise happens in _transform_messages, so any completion call with such a part triggers it deterministically.","commonSituations":"Building multimodal content programmatically where optional fields end up empty; assuming OpenAI's broader file-part schema (which permits other keys) is accepted; putting a local file path under an unsupported key like 'path' or 'filename'.","solutions":["Provide file_id as a fetchable URL: {'type':'file','file':{'file_id':'https://example.com/clip.mp4'}}","Or provide inline data: {'type':'file','file':{'file_data':'data:video/mp4;base64,<...>'}}","If you already have a URL, skip the file part and use {'type':'video_url','video_url':{'url':'https://...'}} directly","Validate content parts before calling litellm.completion so the failure is caught client-side"],"exampleFix":"# before\ncontent = [{\"type\": \"file\", \"file\": {\"filename\": \"clip.mp4\"}}]\nlitellm.completion(model=\"hosted_vllm/Qwen/Qwen2-VL-7B\", messages=[{\"role\": \"user\", \"content\": content}])\n\n# after\ncontent = [{\n    \"type\": \"file\",\n    \"file\": {\"file_id\": \"https://example.com/clip.mp4\"},\n}]\nlitellm.completion(model=\"hosted_vllm/Qwen/Qwen2-VL-7B\", messages=[{\"role\": \"user\", \"content\": content}])","handlingStrategy":"validation","validationCode":"def valid_file_parts(messages: list[dict]) -> bool:\n    for m in messages:\n        for part in m.get(\"content\") or []:\n            if isinstance(part, dict) and part.get(\"type\") == \"file\":\n                f = part.get(\"file\") or {}\n                if not (f.get(\"file_id\") or f.get(\"file_data\")):\n                    return False\n    return True\n\nassert valid_file_parts(messages), \"every file part needs file_id or file_data\"","typeGuard":"from typing import Any\n\ndef is_valid_file_part(part: Any) -> bool:\n    if not isinstance(part, dict) or part.get(\"type\") != \"file\":\n        return True  # not a file part — nothing to check\n    f = part.get(\"file\")\n    return isinstance(f, dict) and bool(f.get(\"file_id\") or f.get(\"file_data\"))","tryCatchPattern":null,"preventionTips":["Prefer the native video_url content part when you already have a URL","Build file parts from a typed dataclass so missing fields surface at construction time","Unit-test message transformation against your real message shapes before sending to hosted_vllm"],"tags":["hosted-vllm","multimodal","video","request-validation","litellm"],"backgroundTag":"missing-required-argument","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}