langchain-ai/langchain · error · ValueError

Keys base64, url, or file_id required for file blocks.

Error message

Keys base64, url, or file_id required for file blocks.

What it means

Raised when a file content block sent to the OpenAI converter contains none of the recognized source keys: `base64`/`source_type=="base64"`, `id`/`file_id`, or `url`. The formatter cannot build an OpenAI file input without knowing where the file bytes or reference live.

Source

Thrown at libs/core/langchain_core/messages/block_translators/openai.py:134

            formatted_block = {"type": "file", "file": file}
            if api == "responses":
                formatted_block = {"type": "input_file", **formatted_block["file"]}
        elif block.get("source_type") == "id" or "file_id" in block:
            # Handle v0 format (IDContentBlock): {"source_type": "id", "id": "...", ...}
            # Handle v1 format (IDCB): {"file_id": "...", ...}
            file_id = block["id"] if "source_type" in block else block["file_id"]
            formatted_block = {"type": "file", "file": {"file_id": file_id}}
            if api == "responses":
                formatted_block = {"type": "input_file", **formatted_block["file"]}
        elif "url" in block:  # Intentionally do not check for source_type="url"
            if api == "chat/completions":
                error_msg = "OpenAI Chat Completions does not support file URLs."
                raise ValueError(error_msg)
            # Only supported by Responses API; return in that format
            formatted_block = {"type": "input_file", "file_url": block["url"]}
        else:
            error_msg = "Keys base64, url, or file_id required for file blocks."
            raise ValueError(error_msg)

    elif block["type"] == "audio":
        if "base64" in block or block.get("source_type") == "base64":
            # Handle v0 format: {"source_type": "base64", "data": "...", ...}
            # Handle v1 format: {"base64": "...", ...}
            base64_data = block["data"] if "source_type" in block else block["base64"]
            audio_format = block["mime_type"].split("/")[-1]
            formatted_block = {
                "type": "input_audio",
                "input_audio": {"data": base64_data, "format": audio_format},
            }
        else:
            error_msg = "Key base64 is required for audio blocks."
            raise ValueError(error_msg)
    else:
        error_msg = f"Block of type {block['type']} is not supported."
        raise ValueError(error_msg)

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Add exactly one of `base64` (+ `mime_type`), `file_id`, or `url` to the file block
  2. Use the v1 constructor `FileContentBlock(...)` which validates a source is present before this converter runs
  3. Log the offending block before invoke() to spot which key was dropped

Example fix

# before
block = {"type": "file", "mime_type": "application/pdf"}

# after
block = {"type": "file", "file_id": "file-abc123", "mime_type": "application/pdf"}
Defensive patterns

Strategy: validation

Validate before calling

def has_file_source(block: dict) -> bool:
    return any(k in block for k in ("base64", "url", "file_id")) or block.get("source_type") == "base64"

Type guard

def is_valid_file_block(block: dict) -> bool:
    return block.get("type") == "file" and (
        "base64" in block or "url" in block or "file_id" in block
    )

Prevention

When it happens

Trigger: Passing `{"type": "file", ...}` with only metadata (`mime_type`, `name`, `id`-as-block-id) and no `file_id`/`base64`/`url`; blocks with typo'd source keys; file blocks stripped by serialization/deserialization that dropped the source field.

Common situations: Hand-written file blocks missing the source key; LangChain-serialized messages where the file payload key was renamed between versions; copying example blocks that were truncated for brevity.

Related errors


AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14). Data as JSON: /api/errors/59214471b9243aae. Report an issue: GitHub.