BoundaryML/baml · error

replace() replacement argument must be a string at

Error message

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

What it means

For the "replace" string method, the second argument (the replacement) must be a String value. The interpreter pattern-matches BamlValueWithMeta::String on args[1] and bails otherwise. Note the method replaces only the first occurrence (JavaScript-like behavior).

Solutions

  1. Convert the replacement to a string (ToString() or string interpolation)
  2. Ensure the second argument is a string literal or string-typed variable
  3. If replacing all occurrences is desired, be aware this method only replaces the first; chain calls or check for a replace-all variant

Example fix

// before
let out = s.replace("{{n}}", count);
// after
let out = s.replace("{{n}}", count.ToString());
Defensive patterns

Strategy: type-guard

Validate before calling

// arg1 must be a string: if (repl is string) { s.replace(search, repl); }

Type guard

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

Try / catch

try { out = s.replace(search, repl); } catch (e) { log(e); }

Prevention

When it happens

Trigger: Calling s.replace(search, nonString), e.g. replace("a", 3), replace("a", null), or passing a numeric LLM output as the replacement.

Common situations: Substituting in a numeric value (count, id, price) without converting it; a null field from a model response used as replacement text.

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

Appendix: source

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

            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" => {
            let value = match receiver {
                BamlValueWithMeta::Float(v, _) => *v,
                BamlValueWithMeta::Int(v, _) => *v as f64,
                _ => bail!(
                    "to_fixed() method only available on floats and ints at {:?}",
                    meta.0
                ),
            };

View on GitHub (pinned to bd85ce9dee)