BerriAI/litellm · error · Exception
Either file_data or file_id must be present in the file mess
Error message
Either file_data or file_id must be present in the file message: {message} What it means
Anthropic file message validation: a message block of type 'file' reached the converter but its file object contains neither file_data (inline base64 bytes) nor file_id (an uploaded Files API id). Anthropic requires exactly one of these, so LiteLLM fails fast and echoes the message.
Source
Thrown at litellm/litellm_core_utils/prompt_templates/factory.py:1971
type="url",
url=file_id,
),
)
elif content_block_type == "image":
return_block_param = AnthropicMessagesImageParam(
type="image",
source=AnthropicContentParamSourceFileId(
type="file",
file_id=file_id,
),
)
elif content_block_type == "container_upload":
return_block_param = AnthropicMessagesContainerUploadParam(type="container_upload", file_id=file_id)
if return_block_param is None:
raise Exception(f"Unable to parse anthropic file message: {message}")
return return_block_param
raise Exception(f"Either file_data or file_id must be present in the file message: {message}")
_EMPTY_TEXT_PLACEHOLDER: Final = "[System: Empty message content sanitised to satisfy protocol]"
def _sanitize_empty_text_content(
message: AllMessageValues,
) -> AllMessageValues:
"""
Case C: Sanitize empty text content
- Replace empty or whitespace-only text content with a placeholder message.
- Handles both string content and list-of-blocks content (rewriting only
the empty text blocks in place; non-text blocks like images are left
untouched).
Returns:
The message with sanitized content if needed, otherwise the original message
"""View on GitHub (pinned to 6c2dcb801b)
Solutions
- Set file_data with base64 bytes: {"type":"file","file":{"filename":"a.pdf","file_data":"data:application/pdf;base64,..."}}
- Or set file_id from the Anthropic Files API: upload the file first and pass the returned id
- If you intended inline content, use the source={type:'base64',...} form instead of a file block
Example fix
# before
content.append({"type": "file", "file": {"filename": "report.pdf"}})
# after
import base64
content.append({"type": "file", "file": {
"filename": "report.pdf",
"file_data": "data:application/pdf;base64," + base64.b64encode(open("report.pdf","rb").read()).decode(),
}}) Defensive patterns
Strategy: type-guard
Validate before calling
def validate_file_message(block: dict) -> None:
f = block.get("file") if isinstance(block, dict) else None
if not (isinstance(f, dict) and (f.get("file_data") or f.get("file_id"))):
raise ValueError(f"file block needs file_data or file_id: {block}") Type guard
from typing import Any
def is_valid_anthropic_file_block(block: Any) -> bool:
return (
isinstance(block, dict)
and block.get("type") == "file"
and isinstance(block.get("file"), dict)
and bool(block["file"].get("file_data") or block["file"].get("file_id"))
) Prevention
- When building file blocks, always set either base64 file_data or an uploaded file_id
- Validate blocks after JSON round-trips
- Use the source={type:'base64'} form for inline bytes if a file block is unnecessary
When it happens
Trigger: {"type": "file", "file": {"filename": "x.pdf"}} with no data or id; file objects built from partial dicts after JSON round-tripping dropped keys; forwarding a file block whose fields were renamed.
Common situations: Constructing file blocks by hand for PDF/image inputs; migrating from inline base64 sources ("source": {...}) to the newer "file" block shape and forgetting both fields; empty file uploads that failed upstream but still got appended.
Related errors
- Unable to parse anthropic file message: {message}
- file_id is required in file_content_request
- File data is required
- WebSearchInterception: missing follow-up messages
- file_id and file_data are both None
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/ca8e9e81e853c93a.
Report an issue: GitHub.