BerriAI/litellm · error · Exception

Either file_data or file_id must be present in the file…

Error message

Either file_data or file_id must be present in the file message: {message}

What it means

The message has a file sub-object but it contains neither file_data nor file_id, so there is nothing to build an Anthropic block from. This is the outer raise (sibling of 794): it fires when the presence check for both keys fails, before any type-specific parsing.

Solutions

  1. Provide file_id (Anthropic Files API id) or base64 file_data in the file sub-object
  2. Validate file blocks before sending - see the type guard below

Example fix

# before
{"type": "file", "file": {"format": "pdf"}}

# after
{"type": "file", "file": {"file_data": "<base64>", "format": "pdf"}}
Defensive patterns

Strategy: type-guard

Validate before calling

def file_messages_have_source(messages: list[dict]) -> bool:
    for m in messages:
        content = m.get("content")
        if not isinstance(content, list):
            continue
        for block in content:
            if isinstance(block, dict) and block.get("type") == "file":
                f = block.get("file") or {}
                if not (f.get("file_id") or f.get("file_data")):
                    return False
    return True

Type guard

from typing import Any, TypeGuard

def has_file_source(block: Any) -> TypeGuard[dict]:
    """True when a file block carries file_id or file_data."""
    if not isinstance(block, dict) or block.get("type") != "file":
        return True
    f = block.get("file")
    return isinstance(f, dict) and bool(f.get("file_id") or f.get("file_data"))

Try / catch

try:
    litellm.completion(model="anthropic/claude-...", messages=messages)
except Exception as e:
    if "Either file_data or file_id must be present" in str(e):
        # attach the uploaded file id (str(e) shows the message) and retry
        messages = attach_file_sources(messages)
    else:
        raise

Prevention

When it happens

Trigger: Sending a file message like {"type": "file", "file": {"format": "pdf"}} with both file_id and file_data absent or None.

Common situations: Building file blocks by hand; consuming file-upload APIs but forgetting to thread the returned id into the message.

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


AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18). Data as JSON: /api/errors/ca8e9e81e853c93a. Report an issue: GitHub.

Appendix: 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 77b7c6c40c)