BoundaryML/baml · critical

undefined function: baml.deep_copy

Error message

undefined function: baml.deep_copy

What it means

Panic when emitting a deep-copy operation: the emitter unconditionally looks up the builtin global "baml.deep_copy" in the globals map and panics if it is absent. The compiler assumes the runtime pre-registers this builtin; if the builtin was never registered (or renamed), deep-copy call sites cannot be lowered.

Solutions

  1. Ensure the runtime prelude (which registers baml.deep_copy) is loaded before compiling/running.
  2. Upgrade or align compiler and runtime versions so the builtin name matches.
  3. Check for typos/renames of the builtin in a custom prelude.
  4. Report the missing-builtin scenario to the BAML maintainers if the prelude is stock.

Example fix

// before: embedding the VM without the builtin prelude
let mut vm = Vm::new();
// after: register builtins first
let mut vm = Vm::new();
vm.register_builtins(); // includes baml.deep_copy
Defensive patterns

Strategy: validation

Validate before calling

// check the builtin is registered before compiling deep-copy sites
if vm.globals().get("baml.deep_copy").is_none() {
    vm.register_builtins();
}

Type guard

fn has_deep_copy_builtin(globals: &HashMap<String, usize>) -> bool {
    globals.contains_key("baml.deep_copy")
}

Try / catch

// panics abort the process; validate environment beforehand
assert!(globals.contains_key("baml.deep_copy"), "runtime prelude not loaded");

Prevention

When it happens

Trigger: Compiling code that performs a deep copy (e.g. deep-cloning a class/dynamic value) while the globals table lacks the "baml.deep_copy" builtin — typically because the runtime prelude wasn't loaded or the builtin was renamed across versions.

Common situations: Version mismatch between the compiler and runtime prelude, embedding the BAML runtime without registering builtins, or a renamed builtin after an upgrade.

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


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

Appendix: source

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

    fn alloc_uint8array(&mut self, bytes: &[u8]) -> Result<(), Self::Error> {
        use std::fmt::Write;
        // Store the byte data as a compile-time constant template, then deep-copy
        // it to produce a mutable TLAB allocation (matching array literal semantics).
        let mut display = String::from("b\"");
        for b in bytes {
            write!(display, "\\x{b:02x}").unwrap();
        }
        display.push('"');
        let obj_idx = self.mint_object(Object::Uint8Array(bytes.to_vec().into()));
        let idx = self.add_constant(ConstValue::Object(ObjectIndex::from_raw(obj_idx)));
        let inst = self.emit(Instruction::LoadConst(idx));
        self.set_operand(inst, OperandMeta::Const(display));
        let deep_copy_idx = self
            .globals
            .get("baml.deep_copy")
            .copied()
            .unwrap_or_else(|| panic!("undefined function: baml.deep_copy"));
        let inst = self.emit(Instruction::Call {
            callee: GlobalIndex::from_raw(deep_copy_idx),
            ntypeargs: 0,
        });
        self.set_operand(inst, OperandMeta::Callable("baml.deep_copy".to_string()));
        Ok(())
    }

    fn alloc_map(
        &mut self,
        key_ty: &TyTemplate,
        value_ty: &TyTemplate,
        len: usize,
    ) -> Result<(), Self::Error> {
        // Push key then value type on top of the entries; the VM's `AllocMap`
        // pops value then key before processing the pairs.
        self.load_type(key_ty)?;
        self.load_type(value_ty)?;

View on GitHub (pinned to bd85ce9dee)