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

When converting an OpenAI-style {'type':'file'} content block (used by Anthropic-style document inputs), litellm reads the 'file' sub-dict and requires either 'file_id' or 'file_data' to be truthy. The code first raises BadRequestError if the 'file' key itself is missing; this ValueError fires when the 'file' dict exists but both file_id and file_data are absent or empty — there is nothing to turn into the image_url/file object it builds next.

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 6c2dcb801b)

Solutions

  1. Include file_id (a URL or provider file reference) or file_data (bytes/Path/tuple) in the file sub-dict.
  2. Validate messages before sending: drop or reject file blocks whose file dict has neither key.
  3. Check your message-building code for the exact key names — they must be 'file_id' / 'file_data' inside 'file'.

Example fix

// before
{'type':'file','file':{'format':'pdf'}}

# after
{'type':'file','file':{'file_id':'https://example.com/doc.pdf','format':'pdf'}}
Defensive patterns

Strategy: validation

Validate before calling

def file_block_valid(block: dict) -> bool:
    f = block.get('file')
    return isinstance(f, dict) and bool(f.get('file_id') or f.get('file_data'))

Try / catch

try:
    resp = litellm.completion(model=m, messages=msgs)
except ValueError as e:
    if 'file_id and file_data are both None' in str(e):
        msgs = strip_or_fill_file_blocks(msgs)
        resp = litellm.completion(model=m, messages=msgs)
    else:
        raise

Prevention

When it happens

Trigger: Sending {'type':'file','file':{}} or {'type':'file','file':{'format':'pdf'}} with no id/data; template code building file blocks conditionally where both branches failed to set a value; None values for both keys.

Common situations: Dynamically constructed messages where the source field is None; frontend forms letting users attach a file but the upload failed silently, leaving an empty file block; refactors renaming 'file_id' to something else (e.g. 'id') breaking the key contract.

Related errors


AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15). Data as JSON: /api/errors/afb4d736e27a12b8. Report an issue: GitHub.