BoundaryML/baml · error · minijinja::Error

InvalidOperation

InvalidOperation

Error message

Invalid delimiter '{}'. Use 'comma', 'tab', or 'pipe'

What it means

BAML's toon encoding filter accepts a 'delimiter' kwarg restricted to the strings 'comma', 'tab', or 'pipe', which map to toon::Delimiter variants. Any other string raises a minijinja InvalidOperation error naming the rejected value and the allowed options.

Solutions

  1. Use one of the accepted names: delimiter="comma", delimiter="tab", or delimiter="pipe".
  2. Check case and whitespace — the match is exact lowercase; 'Tab' or ' tab ' fail.
  3. If you need a different delimiter, post-process the TOON output (e.g. replace the delimiter after encoding).
  4. Remove the delimiter kwarg to use the default delimiter.
  5. Validate user-supplied template kwargs before rendering if delimiter comes from config.

Example fix

// before (template)
{{ rows | toon(delimiter=";") }}
// after
{{ rows | toon(delimiter="pipe") }}  {# or comma / tab #}
Defensive patterns

Strategy: validation

Validate before calling

fn valid_delimiter(d: &str) -> bool {
    matches!(d, "comma" | "tab" | "pipe")
}
if !valid_delimiter(&delimiter) { bail!("delimiter must be comma|tab|pipe"); }

Type guard

fn valid_delimiter(d: &str) -> bool { matches!(d, "comma" | "tab" | "pipe") }

Try / catch

match tpl.render(ctx) {
    Ok(out) => out,
    Err(e) if e.kind() == minijinja::ErrorKind::InvalidOperation
        && e.to_string().contains("Invalid delimiter") => render_with_default_delimiter(),
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Calling the toon filter with delimiter set to anything other than the three accepted names — e.g. delimiter=";", delimiter="\t" (literal tab character), "tab " with whitespace, or capitalized "Tab".

Common situations: Users trying to use semicolons or custom delimiters for TOON output, passing the actual delimiter character instead of its symbolic name, or copying config from another tool with different delimiter vocabulary.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at engine/baml-lib/jinja-runtime/src/lib.rs:148

    value: &minijinja::Value,
    kwargs: &Kwargs,
) -> Result<String, minijinja::Error> {
    let json_value = minijinja_value_to_json(value)
        .map_err(|e| minijinja::Error::new(minijinja::ErrorKind::BadSerialization, e))?;

    let mut options = toon::EncodeOptions::default();

    if let Ok(indent) = kwargs.get::<usize>("indent") {
        options.indent = indent;
    }

    if let Ok(delimiter_str) = kwargs.get::<String>("delimiter") {
        options.delimiter = match delimiter_str.as_str() {
            "comma" => toon::Delimiter::Comma,
            "tab" => toon::Delimiter::Tab,
            "pipe" => toon::Delimiter::Pipe,
            _ => {
                return Err(minijinja::Error::new(
                    minijinja::ErrorKind::InvalidOperation,
                    format!(
                        "Invalid delimiter '{}'. Use 'comma', 'tab', or 'pipe'",
                        delimiter_str
                    ),
                ))
            }
        };
    }

    if let Ok(marker) = kwargs.get::<String>("length_marker") {
        if marker.chars().count() == 1 {
            options.length_marker = marker.chars().next();
        } else {
            return Err(minijinja::Error::new(
                minijinja::ErrorKind::InvalidOperation,
                format!("length_marker must be a single character, got '{}'", marker),
            ));

View on GitHub (pinned to bd85ce9dee)