BoundaryML/baml · error

interface `{}` declares no method `{}` for its default

Error message

interface `{}` declares no method `{}` for its default

What it means

This is a Rust `unreachable!()` panic inside `apply_interface_default_backfill` in baml_compiler2_emit. A deferred backfill entry references a method name that the pooled interface's `methods` list does not contain. The backfill pass assumes any method default it deferred during pooling still exists on the interface when it writes `method.default = Some(entry.default)`. The library panics because this desynchronization indicates a compiler bug, not user error.

Source

Thrown at baml_language/crates/baml_compiler2_emit/src/lib.rs:1238

    method: Name,
    default: ObjectIndex,
}

/// Write each back-filled default into its pooled `Object::Interface`.
fn apply_interface_default_backfill(program: &mut Program, backfill: &[InterfaceDefaultBackfill]) {
    for entry in backfill {
        let Object::Interface(iface) = &mut program.objects[entry.interface] else {
            unreachable!(
                "interface index {} is not an Object::Interface",
                entry.interface.raw()
            )
        };
        let method = iface
            .methods
            .iter_mut()
            .find(|method| method.name == entry.method)
            .unwrap_or_else(|| {
                unreachable!(
                    "interface `{}` declares no method `{}` for its default",
                    iface.name, entry.method
                )
            });
        method.default = Some(entry.default);
    }
}

pub(crate) use emit::compile_mir_function;

fn is_builtin_function_name(name: &str) -> bool {
    matches!(
        name.split('.').next(),
        Some(
            "baml"
                | "boundary"
                | "reflect"
                | "assert"

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Verify every interface method that can carry a `default` is inserted into `iface.methods` before `apply_interface_default_backfill` runs.
  2. Check for renames between default-record time and backfill time; key the backfill by a stable identity (index) rather than `Name` if names can change.
  3. Confirm no pass removes or filters interface methods after backfill entries are created.
  4. If a method default can legitimately target a nonexistent method, replace the `unreachable!` with a diagnostic instead of panicking.

Example fix

// before: default recorded under old method name, method renamed later
backfill.push(InterfaceDefaultBackfill { interface, method: Name::from("to_string"), default });
// after: record after the method list is final, using the final method name
let method = iface.methods.iter().find(|m| m.name == final_name).expect("method pooled");
backfill.push(InterfaceDefaultBackfill { interface, method: method.name.clone(), default });
Defensive patterns

Strategy: validation

Validate before calling

// If embedding the compiler, check the deferred default targets an existing method:
fn default_method_exists(iface: &Interface, method: &Name) -> bool {
    iface.methods.iter().any(|m| &m.name == method)
}

Type guard

// Not applicable to end users; for compiler code prefer a lookup that returns Option
// and surface a compile diagnostic instead of panicking:
fn find_method<'a>(iface: &'a Interface, name: &Name) -> Option<&'a Method> {
    iface.methods.iter().find(|m| &m.name == name)
}

Try / catch

// Panics are not catchable from BAML user code. Embedders can isolate compilation:
let result = std::panic::catch_unwind(|| compile(&source));
if result.is_err() {
    report_internal_compiler_error();
}

Prevention

When it happens

Trigger: Occurs when an `InterfaceDefaultBackfill { interface, method, default }` names a method (`entry.method`) absent from `iface.methods` at backfill time — e.g. the method was renamed, dropped, or never inserted into the interface's method list before backfill runs.

Common situations: Compiler development scenarios: renaming interface methods in the parser/AST without updating deferred-default bookkeeping, filtering or pruning interface methods during lowering, or pooling interfaces before all declared methods are attached.

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