BerriAI/litellm · error · ValueError
file_id and file_data are both None
Error message
file_id and file_data are both None
What it means
A chat message content block with type='file' passed the earlier check (the 'file' sub-dict exists) but that dict contains neither 'file_id' nor 'file_data'. litellm needs at least one of these to build the provider request, so it raises before sending anything.
Solutions
- Pass file_id from a prior file upload (e.g. OpenAI files API id like 'file-abc123')
- Or pass base64 file_data inline
- Check exact key names: the id/data live inside the 'file' sub-object, not on the content block
Example fix
# before
{"type": "file", "file": {"format": "pdf"}}
# after
{"type": "file", "file": {"file_id": "file-abc123", "format": "pdf"}} Defensive patterns
Strategy: type-guard
Validate before calling
def validate_file_blocks(messages: list[dict]) -> None:
for i, msg in enumerate(messages):
content = msg.get("content")
if not isinstance(content, list):
continue
for j, block in enumerate(content):
if block.get("type") == "file":
f = block.get("file") or {}
if not f.get("file_id") and not f.get("file_data"):
raise ValueError(f"messages[{i}].content[{j}]: file block needs file_id or file_data") Type guard
from typing import Any, TypedDict, TypeGuard
class ValidFileBlock(TypedDict):
type: str
file: dict[str, Any]
def is_valid_file_block(block: Any) -> TypeGuard[ValidFileBlock]:
if not isinstance(block, dict) or block.get("type") != "file":
return False
f = block.get("file")
return isinstance(f, dict) and bool(f.get("file_id") or f.get("file_data"))
# usage: blocks = [b for b in content if b.get("type") != "file" or is_valid_file_block(b)] Try / catch
try:
litellm.completion(model=model, messages=messages)
except ValueError as e:
if "file_id and file_data are both None" in str(e):
# fix upstream: attach the uploaded file id, then rebuild the message
attach_file_id(messages)
else:
raise Prevention
- Always thread the id from your file-upload response into file.file_id
- Centralize file-message construction in one helper that asserts the id/data invariant
- Add schema validation (Pydantic/Zod) on inbound user payloads containing file blocks
When it happens
Trigger: Sending a content block like {"type": "file", "file": {"format": "pdf"}} where both file_id and file_data are absent, None, or empty strings.
Common situations: Hand-building file message blocks and forgetting the id; uploading a file but reading the wrong key from the upload response; copy-pasting doc examples that omit file_id.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Either file_data or file_id must be present in the file…
- `prompt` must be a non-empty string or a non-empty list of…
- Amazon Nova Canvas requires a text prompt. Pass a non-empty…
- audience must be provided unless…
- BFL error
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/afb4d736e27a12b8.
Report an issue: GitHub.
Appendix: source
Thrown at litellm/litellm_core_utils/prompt_templates/common_utils.py:1376
Migrate file to image_url
"""
from litellm.types.llms.openai import (
ChatCompletionImageObject,
ChatCompletionImageUrlObject,
)
file_sub: Final = message.get("file")
if file_sub is None:
raise litellm.BadRequestError(
message="Content block has type='file' but is missing the required 'file' field",
model=None,
llm_provider=None,
)
file_id: Final = file_sub.get("file_id")
file_data: Final = file_sub.get("file_data")
format: Final = file_sub.get("format")
if not file_id and not file_data:
raise ValueError("file_id and file_data are both None")
image_url_object: Final = ChatCompletionImageObject(
type="image_url",
image_url=ChatCompletionImageUrlObject(
url=cast(str, file_id or file_data),
),
)
if format and isinstance(image_url_object["image_url"], dict):
image_url_object["image_url"]["format"] = format
return image_url_object
def get_last_user_message(messages: list[AllMessageValues]) -> str | None:
"""
Get the last consecutive block of messages from the user.
Example:
messages = [
{"role": "user", "content": "Hello, how are you?"},View on GitHub (pinned to 77b7c6c40c)