BoundaryML/baml · error

OpenAI transcription prompt is ambiguous: both properties.pr

Error message

OpenAI transcription prompt is ambiguous: both properties.prompt and rendered text were provided

What it means

The transcription `prompt` field can come from two sources: an explicit `prompt` client property or rendered text from the chat messages. If both are present the intended prompt is ambiguous, so build_transcription_parts refuses to silently pick one and bails.

Source

Thrown at engine/baml-runtime/src/internal/llm_client/primitive/openai/types.rs:102

        .pop()
        .expect("audio_parts length was already validated");
    let mime = audio.mime_type_as_ok()?;
    let file_bytes = match &audio.content {
        BamlMediaContent::Base64(media_b64) => BASE64_STANDARD
            .decode(&media_b64.base64)
            .context("Failed to decode transcription audio as base64")?,
        BamlMediaContent::Url(_) | BamlMediaContent::File(_) => {
            bail!("OpenAI transcription audio must be resolved to base64 before request building")
        }
    };

    let mut fields = BamlMap::new();
    let model = required_string_field(properties, "model")?;
    fields.insert("model".to_string(), model.clone());

    let property_prompt = optional_string_field(properties, "prompt")?;
    if property_prompt.is_some() && !text_parts.is_empty() {
        bail!("OpenAI transcription prompt is ambiguous: both properties.prompt and rendered text were provided");
    }
    let rendered_prompt = (!text_parts.is_empty()).then(|| text_parts.join("\n"));
    if let Some(prompt) = property_prompt.or(rendered_prompt) {
        fields.insert("prompt".to_string(), prompt);
    }

    if let Some(language) = optional_string_field(properties, "language")? {
        fields.insert("language".to_string(), language);
    }
    if let Some(response_format) = optional_response_format(properties, &model)? {
        fields.insert("response_format".to_string(), response_format);
    }
    if let Some(temperature) = optional_temperature(properties)? {
        fields.insert("temperature".to_string(), temperature);
    }

    Ok(TranscriptionParts {
        file_bytes,

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Remove the `prompt` property from the client options and keep the prompt text in the BAML template.
  2. Or remove the rendered text from the template, keeping only the audio part, and rely on the client's `prompt` property.
  3. Merge the hint text into whichever source you keep.

Example fix

// before
client<T> { provider openai options { model "whisper-1" prompt "glossary terms" } }
prompt #"User audio: {{ audio }} Please transcribe carefully."#
// after
client<T> { provider openai options { model "whisper-1" } }
prompt #"{{ _.role('user') }} {{ audio }}"#
Defensive patterns

Strategy: validation

Validate before calling

// Check config + rendered prompt for a conflicting prompt source
function assertSinglePromptSource(clientOptions, renderedMessages) {
  const hasPropPrompt = typeof clientOptions.prompt === "string";
  const hasText = renderedMessages.some(m => m.parts.some(p => p.type === "text" && p.text.trim() !== ""));
  if (hasPropPrompt && hasText) throw new Error("Remove either the client 'prompt' option or the rendered prompt text");
}

Prevention

When it happens

Trigger: A transcription client options block that sets `prompt "..."` while the BAML function prompt also renders non-empty text parts alongside the audio media part.

Common situations: Adding instructions/hints in the BAML prompt text while also having set the OpenAI-style `prompt` option in the client config; copying a client config that already had a prompt property and then editing the template to add text.

Related errors


AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12). Data as JSON: /api/errors/42238f1b472c1397. Report an issue: GitHub.