BoundaryML/baml · error

split() argument must be a string at {:?}

Error message

split() argument must be a string at {:?}

What it means

The split method's delimiter argument must be a string. The interpreter destructures args[0] as a String value and bails with this message if it is an int, bool, list, or other non-string type. No implicit coercion is performed.

Source

Thrown at engine/baml-compiler/src/thir/interpret.rs:2936

                bail!("endsWith() method takes exactly 1 argument at {:?}", meta.0);
            }
            let BamlValueWithMeta::String(suffix, _) = &args[0] else {
                bail!("endsWith() argument must be a string at {:?}", meta.0);
            };
            Ok(BamlValueWithMeta::Bool(
                s.ends_with(suffix.as_str()),
                meta.clone(),
            ))
        }
        "split" => {
            let BamlValueWithMeta::String(s, _) = receiver else {
                bail!("split() method only available on strings at {:?}", meta.0);
            };
            if args.len() != 1 {
                bail!("split() method takes exactly 1 argument at {:?}", meta.0);
            }
            let BamlValueWithMeta::String(delimiter, _) = &args[0] else {
                bail!("split() argument must be a string at {:?}", meta.0);
            };
            let parts: Vec<BamlValueWithMeta<ExprMetadata>> = s
                .split(delimiter.as_str())
                .map(|part| BamlValueWithMeta::String(part.to_string(), meta.clone()))
                .collect();
            Ok(BamlValueWithMeta::List(parts, meta.clone()))
        }
        "substring" => {
            let BamlValueWithMeta::String(s, _) = receiver else {
                bail!(
                    "substring() method only available on strings at {:?}",
                    meta.0
                );
            };
            if args.len() != 2 {
                bail!(
                    "substring() method takes exactly 2 arguments at {:?}",
                    meta.0

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Quote the delimiter or convert it to a string (e.g. n.to_string()) before passing it to split.
  2. Verify the runtime type of the delimiter expression at the failing call site.
  3. Add a type guard if the delimiter can be non-string at runtime.

Example fix

// before
let parts = s.split(year); // year: int

// after
let parts = s.split(year.to_string());
Defensive patterns

Strategy: type-guard

Validate before calling

// ensure the delimiter is a string before split
// delimiter must be string: quote literals, convert numbers

Type guard

fn is_string(v: BamlValue) -> bool { matches!(v, BamlValue::String(_)) }

Try / catch

match result {
  Err(e) if e.to_string().contains("split() argument must be a string") => use_default_delimiter,
  other => other,
}

Prevention

When it happens

Trigger: Calling s.split(1), s.split(null), or passing a non-string variable/expression as the delimiter in a BAML expression.

Common situations: Numeric delimiters (e.g. splitting on a year or ID) not quoted; delimiter coming from extracted data typed as non-string; accidental reuse of a variable holding a list where a string was intended.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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