BoundaryML/baml · error

interface body has no Pass-1 slot: {item}

Error message

interface body has no Pass-1 slot: {item}

What it means

During the emit pass, an interface-machinery body (`ItemRef::InterfaceBody`) must already have a global slot assigned in Pass 1, recorded in `interface_body_slots` keyed by the body's declaration. This panic means the slot map has no entry for that declaration. Per the code comments, Pass 1 is supposed to slot every interface body declaration the compiler database sees, so a miss is an internal invariant violation, not user error.

Source

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

    /// Pass-1 global slot for a function item.
    ///
    /// An interface-machinery body resolves by its DECLARATION
    /// ([`baml_compiler2_mir::InterfaceBodyRef::decl`]) through [`Self::interface_body_slots`] —
    /// its rendered spelling is display-only and keys nothing. Every other
    /// item resolves by its rendered name through [`Self::globals`]; `None`
    /// there means the callee is not statically addressable (the caller falls
    /// back to an indirect call). A body missing its slot is an internal
    /// error: `ItemRef::InterfaceBody` only exists for declarations this database
    /// sees, and Pass 1 slots every one of them.
    fn try_function_global_index(
        &mut self,
        item: &baml_compiler2_mir::ItemRef<'ctx>,
    ) -> Option<usize> {
        if let baml_compiler2_mir::ItemRef::InterfaceBody(body) = item {
            let slot = *self
                .interface_body_slots
                .get(&body.decl)
                .unwrap_or_else(|| panic!("interface body has no Pass-1 slot: {item}"));
            // The body's rendered spelling is display-only for resolution, but
            // its last segment (the method name) is exactly what the declaring
            // file's `defined_names` produces — the incremental edge grain.
            self.references.record(&item.to_string());
            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,

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Run a clean (non-incremental) compile to confirm it is a stale-incremental-state issue, then clear the incremental cache
  2. Check that the interface declaration was present when Pass 1 assigned `interface_body_slots`; compare the Pass-1 declaration set against the emitting set
  3. If you just added a method to an interface, rebuild the whole package rather than relying on incremental output
  4. Report a compiler bug with the BAML source and the item text from the panic message

Example fix

// before (opaque panic on stale incremental state)
$ baml build
// after (force full rebuild)
$ baml clean && baml build
Defensive patterns

Strategy: validation

Validate before calling

// before compiling, assert every InterfaceBody declaration has a Pass-1 slot
for item in all_items {
    if let ItemRef::InterfaceBody(body) = item {
        assert!(interface_body_slots.contains_key(&body.decl), "unslotted interface body: {item}");
    }
}

Try / catch

// run compilation in a worker and surface panics as diagnostics
match std::panic::catch_unwind(|| compile(inputs)) {
    Ok(out) => out,
    Err(_) => diagnose_and_rebuild_from_scratch(),
}

Prevention

When it happens

Trigger: Emitting code that references an interface method body when `interface_body_slots` was populated in Pass 1 without that declaration — e.g. the declaration was added after Pass 1 ran (incremental recompile that added a new interface method), a cross-package/cross-file interface whose body was never slotted, or a stale compiler database after an edit.

Common situations: Incremental compilation after editing an interface to add methods; compiler caching keyed incorrectly so a fresh declaration skipped Pass 1; parallel emit workers seeing a declaration set that differs from the Pass-1 serial run.

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/0c00f3a18197f162. Report an issue: GitHub.