BoundaryML/baml · error

{what}: {item}

Error message

{what}: {item}

What it means

`function_global_index` is the panicking wrapper around `try_function_global_index`: when a function item does not resolve to a Pass-1 global slot (it is missing from the `globals` map by its rendered name), the compiler aborts with the caller-supplied `what` context (e.g. "undefined function"). The code documents that a `None` from `try_function_global_index` normally means the callee is not statically addressable and callers should fall back to an indirect call; this wrapper is used on paths where resolution is required.

Source

Thrown at baml_language/crates/baml_compiler2_emit/src/emit.rs:2066

            return Some(slot);
        }
        let rendered = item.to_string();
        let slot = self.globals.get(&rendered).copied();
        if slot.is_some() {
            self.references.record(&rendered);
        }
        slot
    }

    /// [`Self::try_function_global_index`], panicking with `what` when the
    /// item does not resolve.
    fn function_global_index(
        &mut self,
        item: &baml_compiler2_mir::ItemRef<'ctx>,
        what: &str,
    ) -> usize {
        self.try_function_global_index(item)
            .unwrap_or_else(|| panic!("{what}: {item}"))
    }

    /// Push a function reference as a value: a pooled, interned
    /// `Object::GenericFunction` wrapper over the function's global slot
    /// (empty `type_args` for a plain reference). Interning by
    /// (function, `type_args`) over the shared object pool makes identical
    /// references share ONE pooled object → pointer-stable identity
    /// (`greet === greet`, `foo<int> === foo<int>`).
    ///
    /// Serial emit scans the whole program pool here, so wrappers minted by
    /// EARLIER functions are reused too. Parallel emit scans only this
    /// worker's fragment; the serial merge replays the cross-function dedup
    /// in original function order (see `merge_function_fragment`),
    /// reproducing the exact serial candidate set and pool layout.
    fn emit_pooled_function_value(
        &mut self,
        item: &baml_compiler2_mir::ItemRef<'ctx>,
        type_args: &[baml_type::RealizedTy],

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Verify the referenced function exists and is part of the compiled package set; add the missing package/module to the compilation
  2. Clean incremental caches and rebuild so Pass 1 re-slots all current functions
  3. Check whether the function was renamed; update the reference at the BAML source level
  4. If the callee can legitimately be unresolvable, switch the call site to the indirect-call fallback via `try_function_global_index` instead of the panicking wrapper

Example fix

// before
let global_idx = self.function_global_index(item, "undefined function");
// after
match self.try_function_global_index(item) {
    Some(global_idx) => { /* direct reference */ }
    None => { /* fall back to indirect call */ }
}
Defensive patterns

Strategy: validation

Validate before calling

// pre-flight: confirm every referenced function resolves in this compilation unit
let unresolved: Vec<_> = referenced_functions
    .iter()
    .filter(|f| !globals.contains_key(&f.to_string()))
    .collect();
if !unresolved.is_empty() {
    return Err(format!("unresolved functions: {:?}", unresolved));
}

Try / catch

match std::panic::catch_unwind(|| emit_function(item)) {
    Ok(_) => /* direct emit */,
    Err(_) => /* fall back to indirect call via try_function_global_index */,
}

Prevention

When it happens

Trigger: Emitting a function value or direct call to a function name absent from the `globals` slot map — e.g. calling a function defined in a package not registered in this compilation context, referencing a function that was deleted/renamed while stale incremental state persists, or a `Constant::Function`/`GenericFunction` whose item was never slotted by Pass 1.

Common situations: Cross-package BAML references to functions that aren't compiled into the current unit; renamed functions with stale caches; typos at the MIR level after a refactor of the function-name rendering (`ItemRef::to_string`) so the lookup key no longer matches the Pass-1 key.

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


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