BoundaryML/baml · error
undefined variable
Error message
undefined variable: {name} What it means
The BAML compiler's code generator failed to resolve a variable name while compiling an expression. Any name must be either a local variable (compiled into LoadVar) or a global (a class/function registered in globals); if neither lookup succeeds, the compiler panics because the semantic layer should have rejected unresolved names earlier. This represents an identifier that is not in scope at the point of use.
Solutions
- Declare the variable before use (let or the block's parameter list) and fix any spelling mismatch with the declaration
- Check that the variable is defined in the same scope where it is referenced; BAML block scoping is lexical
- If the symbol should be a global (class or function), confirm it is defined at file scope and imported/visible in this file
- If this occurs with valid code, it may be a compiler bug — report it with the .baml source that triggers the panic
Example fix
// before let prompt = "Hello " ++ usermame // after let prompt = "Hello " ++ username
Defensive patterns
Strategy: validation
Validate before calling
fn validate_var_defined(name: &str, locals: &HashSet<&str>, globals: &HashSet<&str>) -> Result<(), String> {
if locals.contains(name) || globals.contains(name) { Ok(()) }
else { Err(format!("variable '{}' is not defined in scope", name)) }
} Type guard
fn is_defined(name: &str, scope: &Scope) -> bool { scope.locals.contains_key(name) || scope.globals.contains_key(name) } Prevention
- Compile early and often so undefined references surface immediately
- Keep variable declarations and uses in the same lexical block
- Search the file for the identifier before renaming or deleting declarations
- Enable editor/lint support for .baml to catch unresolved identifiers before compilation
When it happens
Trigger: Compiling a BAML expression that references an identifier never declared (typo, use-before-declaration, reference to a symbol from another scope, or a variable only defined inside a branch the compiler path skipped). The name is absent from both self.locals and self.globals in compile_expression.
Common situations: Typos in variable names inside expression blocks; referencing a function parameter that was removed or renamed; using a variable defined in a different block scope; mid-refactor states where a declaration was deleted but uses remain.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- array access should be either map or array.
- expressions that evaluate to functions are not supported yet
- field access must be on classes, but expr
- Field access on non-class type
- method calls must be identifiers
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/28e6e55431cec650.
Report an issue: GitHub.
Appendix: source
Thrown at engine/baml-compiler/src/codegen.rs:1213
};
self.emit(Instruction::LoadField(field_index));
}
other => panic!(
"field access must be on classes, but expr `{}` got: {other:?}",
base.dump_str()
),
}
}
thir::Expr::Var(name, _) => {
if let Some(&index) = self.locals.get(name) {
self.emit(Instruction::LoadVar(index));
} else if let Some(class) = self.globals.get(name) {
self.emit(Instruction::LoadGlobal(*class));
} else {
panic!("undefined variable: {name}");
}
}
thir::Expr::List(elements, _) => {
for element in elements {
self.compile_expression(element);
}
self.emit(Instruction::AllocArray(elements.len()));
}
thir::Expr::Map(pairs, _) => {
// Maps are not yet implemented in bytecode
// have N keys, N values.
// keys are popped first, so we first compute the values.
for (_, value) in pairs {
self.compile_expression(value);
}View on GitHub (pinned to bd85ce9dee)