langchain-ai/langchain · error · ValueError

Key base64 is required for audio blocks.

Error message

Key base64 is required for audio blocks.

What it means

Raised when an audio content block sent to the OpenAI converter has neither a `base64` key nor `source_type == "base64"`. OpenAI's audio input format (`input_audio`) requires inline base64 data plus a format derived from `mime_type`; audio supplied by URL or file ID is not supported on this path.

Source

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

            # 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)

    return formatted_block


# v1 / Chat Completions
def _convert_to_v1_from_chat_completions(
    message: AIMessage,
) -> list[types.ContentBlock]:
    """Mutate a Chat Completions message to v1 format."""
    content_blocks: list[types.ContentBlock] = []
    if isinstance(message.content, str):
        if message.content:
            content_blocks = [{"type": "text", "text": message.content}]
        else:
            content_blocks = []

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Inline the audio: fetch/encode the bytes and pass `base64` plus `mime_type` (e.g. `audio/wav`)
  2. If the audio only exists as a URL, download it first (`requests.get(url).content`) and base64-encode it
  3. Use `AudioContentBlock(base64=..., mime_type="audio/wav")` to build valid blocks

Example fix

# before
block = {"type": "audio", "url": "https://example.com/clip.wav"}

# after
import base64, requests
b64 = base64.b64encode(requests.get("https://example.com/clip.wav").content).decode()
block = {"type": "audio", "base64": b64, "mime_type": "audio/wav"}
Defensive patterns

Strategy: validation

Validate before calling

def has_audio_b64(block: dict) -> bool:
    return "base64" in block or block.get("source_type") == "base64"

Type guard

def is_inline_audio_block(block: dict) -> bool:
    return block.get("type") == "audio" and ("base64" in block or block.get("source_type") == "base64")

Prevention

When it happens

Trigger: Passing `{"type": "audio", "url": ...}` or `{"type": "audio", "file_id": ...}` (neither base64 key nor base64 source_type) to an OpenAI model or `convert_to_openai_data_block`.

Common situations: Assuming audio blocks mirror image blocks and accept URLs; passing audio recorded elsewhere as a link; blocks converted from other providers that store audio as a reference rather than inline bytes.

Related errors


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