BoundaryML/baml · error
undefined global item: {name_str}
Error message
undefined global item: {name_str} What it means
When emitting a `Constant::GlobalItem` (a non-function global such as a client or a top-level `let`), the compiler reads the global slot assigned by the `$init` pass from the `globals` map keyed by the item's rendered name. This panic fires when the name is absent — the global was never assigned a slot in the current compilation unit. It is effectively an "undefined global" compiler-internal error, analogous to an unresolved symbol at link time.
Source
Thrown at baml_language/crates/baml_compiler2_emit/src/emit.rs:2185
Constant::Function(item_ref) => {
// A plain function reference as a VALUE. Pooled exactly like
// `Constant::GenericFunction`, with EMPTY type args: every
// function-pointer value on the heap is a wrapper object
// (`GenericFunction`/`Closure`/`BoundMethod`/`HostClosure`),
// and a raw `Object::Function` is never a data value — the
// invariant `value_concrete_ty` / `callable_signature` rely
// on. Interning keeps `greet === greet` pointer-stable, as a
// direct `LoadGlobal` of the function object did before.
self.emit_pooled_function_value(item_ref, &[]);
}
Constant::GlobalItem(item_ref) => {
// A non-function global item (a client, a top-level `let`,
// ...): read the value `$init` stored in its slot, unwrapped.
let name_str = item_ref.to_string();
let global_idx = *self
.globals
.get(&name_str)
.unwrap_or_else(|| panic!("undefined global item: {name_str}"));
self.references.record(&name_str);
let inst = self.emit(Instruction::LoadGlobal(GlobalIndex::from_raw(global_idx)));
self.set_operand(inst, OperandMeta::Global(name_str));
}
Constant::GenericFunction { item, type_args } => {
// `foo<int>` as a value: the same pooled wrapper, carrying its
// concrete type arguments so calling it seeds `frame.type_args`.
self.emit_pooled_function_value(item, type_args);
}
Constant::EnumVariant { enum_ref, variant } => {
let enum_name_str = enum_ref.to_string();
// Gracefully handle undefined enum references (e.g. cross-package
// references that aren't registered in this compilation context).
// Emit a Null constant so tests don't panic; runtime will fail
// if the code path is actually executed.
let enum_obj_idx = self.enum_object_indices.get(&enum_name_str).copied();
if enum_obj_idx.is_some() {
self.references.record(&enum_name_str);View on GitHub (pinned to bd85ce9dee)
Solutions
- Ensure the referenced client/top-level `let` is defined in a package included in the current compilation
- Clear incremental caches and do a full rebuild so `$init` re-slots all globals
- Check for renames/typos of the global name in the source
- If the name comes from another package, confirm cross-package registration/exports are set up
- Report a compiler bug if a defined global still triggers the panic (key-mismatch regression)
Example fix
// before (BAML referencing a client that isn't in the compiled set)
client MyClient { ... } // defined in another, uncompiled package
// after
// include the package defining MyClient in the compilation, or define it locally:
client MyClient { provider "openai" options { model "gpt-4o" } } Defensive patterns
Strategy: validation
Validate before calling
// pre-flight: every referenced global item must have a slot
for name in referenced_global_names {
assert!(globals.contains_key(&name), "global not in compilation unit: {name}");
} Try / catch
match std::panic::catch_unwind(|| compile(inputs)) {
Ok(out) => out,
Err(_) => {
clean_incremental_cache();
compile(inputs) // full rebuild after stale-state panic
}
} Prevention
- Define referenced clients and top-level lets inside the compiled package set
- Rebuild fully after deleting or renaming globals
- Verify cross-package registrations before referencing external clients
- Keep ItemRef::to_string rendering stable between slot assignment and lookup
When it happens
Trigger: Referencing a top-level `let` or client from code being emitted when that item's slot is missing — e.g. the global lives in a package not included in this compilation context, the global was removed but a stale incremental fragment still references it, or the rendered name key diverges between slot assignment and lookup.
Common situations: Cross-package references to clients/top-level values not registered in this compile; stale incremental state after deleting or renaming a client or top-level `let`; compiler refactors changing `ItemRef::to_string` so the two maps use different key spellings.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- type_arg_templates count fits in u16
- ntypeargs fits in u16
- interface body has no Pass-1 slot: {item}
- {what}: {item}
- undefined variant: {enum_name_str}.{variant_str}
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/8e32af4b5941a864.
Report an issue: GitHub.