BoundaryML/baml · error

replace() search argument must be a string at

Error message

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

What it means

For the "replace" string method, the first argument (the search substring) must be a String value. The interpreter pattern-matches BamlValueWithMeta::String on args[0] and bails otherwise. Plain substring search only — no regex or non-string needles.

Solutions

  1. Wrap the search argument in a string (e.g. ToString(), or quote the literal)
  2. Ensure the argument expression is statically typed/annotated as string
  3. Convert numeric search terms to their string form before the call

Example fix

// before
let out = s.replace(id, "REDACTED");
// after
let out = s.replace(id.ToString(), "REDACTED");
Defensive patterns

Strategy: type-guard

Validate before calling

// arg0 must be a string: if (search 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(nonString, replacement), e.g. replace(42, "x"), replace(someMap, "x"), or passing a null from an LLM field as the search term.

Common situations: Passing numbers (like IDs) directly as the search argument; a variable inferred as int/float being used where a string literal was expected.

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

Appendix: source

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

            };

            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" => {
            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)