{"record":{"id":"53a7d10cd0b94577","repo":"BoundaryML/baml","slug":"openai-transcriptions-require-exactly-one-audio-media-part","errorCode":null,"errorMessage":"OpenAI transcriptions require exactly one audio media part, got {}","messagePattern":"OpenAI transcriptions require exactly one audio media part, got (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/baml-runtime/src/internal/llm_client/primitive/openai/types.rs","lineNumber":77,"sourceCode":"    let messages = match prompt {\n        either::Either::Right(messages) => messages,\n        either::Either::Left(_) => {\n            bail!(\"OpenAI transcriptions require chat messages with exactly one audio media part\")\n        }\n    };\n\n    reject_reserved_request_fields(properties)?;\n\n    let mut audio_parts = Vec::new();\n    let mut text_parts = Vec::new();\n    for message in messages {\n        for part in &message.parts {\n            collect_transcription_prompt_parts(part, &mut audio_parts, &mut text_parts)?;\n        }\n    }\n\n    if audio_parts.len() != 1 {\n        bail!(\n            \"OpenAI transcriptions require exactly one audio media part, got {}\",\n            audio_parts.len()\n        );\n    }\n\n    let audio = audio_parts\n        .pop()\n        .expect(\"audio_parts length was already validated\");\n    let mime = audio.mime_type_as_ok()?;\n    let file_bytes = match &audio.content {\n        BamlMediaContent::Base64(media_b64) => BASE64_STANDARD\n            .decode(&media_b64.base64)\n            .context(\"Failed to decode transcription audio as base64\")?,\n        BamlMediaContent::Url(_) | BamlMediaContent::File(_) => {\n            bail!(\"OpenAI transcription audio must be resolved to base64 before request building\")\n        }\n    };\n","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/engine/baml-runtime/src/internal/llm_client/primitive/openai/types.rs#L59-L95","documentation":"After collecting media parts from all chat messages, build_transcription_parts requires exactly one audio media part because an OpenAI transcription request carries a single audio file. Zero audio parts means nothing to transcribe; more than one is ambiguous, so the count is validated and the actual number reported.","triggerScenarios":"A chat prompt with no media parts at all; a prompt with two or more audio parts; multiple user messages each attaching audio, all fed to a transcription-configured client.","commonSituations":"Forgetting to include the audio variable in the BAML prompt template; concatenating prompts that each embed audio; building messages programmatically and appending audio twice.","solutions":["Include exactly one audio media part in the prompt (e.g. {{ audio }} in a single user message).","Remove duplicate audio parts if the prompt template references the audio more than once.","Verify the media variable is actually an Audio and rendered as a media part, not plain text."],"exampleFix":"// before (two audio parts)\nprompt #\"{{ audio }} {{ audio2 }}\"#\n// after\nprompt #\"\n  {{ _.role('user') }}\n  {{ audio }}\n  Please transcribe.\n\"#","handlingStrategy":"validation","validationCode":"// Count audio media parts in the rendered prompt before calling the function\nfunction assertSingleAudio(messages) {\n  const audioParts = messages.flatMap(m => m.parts).filter(p => p.type === \"audio\");\n  if (audioParts.length !== 1) {\n    throw new Error(`Transcription prompt must contain exactly one audio part, got ${audioParts.length}`);\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Reference the audio variable exactly once in the prompt template.","Do not compose transcription prompts by concatenating templates that each include media.","Add a unit test that renders every transcription prompt and asserts one audio part."],"tags":["openai","transcription","audio","baml"],"backgroundTag":"invalid-argument-value","analyzedSha":"bd85ce9dee1463ff04d27efd20531013a4ff46c1","analyzedAt":"2026-09-12T03:38:25.718Z","contentChangedAt":"2026-09-12T03:38:25.718Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}