BoundaryML/baml · error

replace() method only available on strings at {:?}

Error message

replace() method only available on strings at {:?}

What it means

The BAML interpreter's evaluate_method_call hit the "replace" string method with a receiver value that is not a String. The library only defines replace() on string values, so it bails with the source location (meta.0) attached. This is a runtime type mismatch between the declared/actual receiver type and the method called.

Source

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

            }
            let BamlValueWithMeta::Int(start, _) = &args[0] else {
                bail!("substring() start argument must be an int at {:?}", meta.0);
            };
            let BamlValueWithMeta::Int(end, _) = &args[1] else {
                bail!("substring() end argument must be an int at {:?}", meta.0);
            };

            let start = (*start as usize).min(s.len());
            let end = (*end as usize).min(s.len()).max(start);

            Ok(BamlValueWithMeta::String(
                s[start..end].to_string(),
                meta.clone(),
            ))
        }
        "replace" => {
            let BamlValueWithMeta::String(s, _) = receiver else {
                bail!("replace() method only available on strings at {:?}", meta.0);
            };
            if args.len() != 2 {
                bail!("replace() method takes exactly 2 arguments at {:?}", meta.0);
            }
            let BamlValueWithMeta::String(search, _) = &args[0] else {
                bail!("replace() search argument must be a string at {:?}", meta.0);
            };
            let BamlValueWithMeta::String(replacement, _) = &args[1] else {
                bail!(
                    "replace() replacement argument must be a string at {:?}",
                    meta.0
                );
            };
            // Replace first occurrence only (matching JavaScript behavior)
            let result = s.replacen(search.as_str(), replacement.as_str(), 1);
            Ok(BamlValueWithMeta::String(result, meta.clone()))
        }
        "to_fixed" => {

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Check the receiver's actual value/type at that source span and ensure it is a string before calling .replace()
  2. Add a type annotation or cast so the value is statically a string (e.g. coalesce null to "" or use string interpolation)
  3. If the value can be non-string, branch on its type or use a checked conversion instead of calling the method unconditionally

Example fix

// before (value may be int/null)
let cleaned = value.replace("-", "_");
// after
let cleaned = value.ToString().replace("-", "_");
Defensive patterns

Strategy: type-guard

Validate before calling

// before calling .replace
if (value != null && value is string) { value.replace("a","b"); }

Type guard

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

Try / catch

try { formatted = value.replace(search, repl); } catch (e) { log(e); formatted = null; }

Prevention

When it happens

Trigger: Calling .replace(...) on a non-string value at runtime, e.g. on an int, float, bool, null, map, or array — typically when the receiver came from an LLM response field, a media() result, or a variable whose type the typechecker did not constrain.

Common situations: Prompting an LLM that returns a number or null where the developer assumed a string, then calling .replace() on it inside a BAML expression; iterating mixed-type arrays and calling string methods on elements.

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/d5310b28fe20fe8b. Report an issue: GitHub.