BoundaryML/baml · error · anyhow::Error

{diagnostics}

Error message

{diagnostics}

What it means

add_baml() parses user-supplied BAML source with parse_type_builder_contents_from_str and collects syntax diagnostics; if any errors were recorded during parsing, the whole call is aborted with the pretty-printed diagnostics. This means the string passed to type_builder.add_baml(...) is not syntactically valid BAML. The library fails fast at parse time so invalid dynamic types never reach the runtime.

Source

Thrown at engine/baml-runtime/src/type_builder/mod.rs:677

    /// `type_builder.add_baml("BAML CODE")`
    pub fn add_baml(&self, baml: &str, rt: &BamlRuntime) -> anyhow::Result<()> {
        use internal_baml_core::{
            internal_baml_ast::parse_type_builder_contents_from_str,
            internal_baml_diagnostics::{Diagnostics, SourceFile},
            ir::repr::IntermediateRepr,
            run_validation_pipeline_on_db, validate_type_builder_entries,
        };

        let path = std::path::PathBuf::from("TypeBuilder::add_baml");
        let source = SourceFile::from((path.clone(), baml));

        let mut diagnostics = Diagnostics::new(path);
        diagnostics.set_source(&source);

        let type_builder_entries = parse_type_builder_contents_from_str(baml, &mut diagnostics)?;

        if diagnostics.has_errors() {
            anyhow::bail!("{}", diagnostics.to_pretty_string());
        }

        // TODO: A bunch of mem usage here but at least we drop this one at the
        // end of the function, unlike scoped DBs for type builders.
        let mut scoped_db = rt.db.clone();

        let local_ast =
            validate_type_builder_entries(&mut diagnostics, &scoped_db, &type_builder_entries);
        scoped_db.add_ast(local_ast);

        if let Err(d) = scoped_db.validate(&mut diagnostics) {
            diagnostics.push(d);
            anyhow::bail!("{}", diagnostics.to_pretty_string());
        }

        run_validation_pipeline_on_db(&mut scoped_db, &mut diagnostics);

        if diagnostics.has_errors() {

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Read the pretty-printed diagnostics in the error message; they point to the exact line/column in the snippet that failed to parse.
  2. Fix the syntax error in the string passed to add_baml (missing braces, bad keyword, malformed field).
  3. If the snippet is generated, print it before calling add_baml and inspect it as a .baml file in an editor with BAML syntax support.
  4. Keep the dynamic snippet minimal and mirror a working .baml file's syntax instead of writing BAML from scratch.

Example fix

// before
await tb.add_baml(`class Foo { prop string`);
// after
await tb.add_baml(`class Foo {\n  prop string\n}`);
Defensive patterns

Strategy: validation

Validate before calling

function validateBamlSnippet(src) {
  if (typeof src !== 'string' || src.trim() === '') throw new Error('add_baml requires non-empty BAML source');
  if ((src.split('{').length) !== (src.split('}').length)) throw new Error('Unbalanced braces in BAML snippet');
  return true;
}
validateBamlSnippet(bamlSrc);

Type guard

const isBamlSource = (v) => typeof v === 'string' && v.trim().length > 0;

Prevention

When it happens

Trigger: Calling type_builder.add_baml(baml_string) (from Python/TS/Ruby wrappers) where baml_string fails BAML parsing, e.g. a malformed class/enum/type-alias declaration inside the dynamic BAML snippet.

Common situations: Hand-built or interpolated BAML strings with missing braces, typos in keywords, unquoted field defaults, or template-generated snippets that produce broken syntax; users dynamically composing BAML from config or LLM output.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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