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
- Verify every interface method that can carry a `default` is inserted into `iface.methods` before `apply_interface_default_backfill` runs.
- 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.
- Confirm no pass removes or filters interface methods after backfill entries are created.
- 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
- Key deferred defaults by stable method identity (index) rather than a renameable `Name`.
- Finalize the interface method list before creating backfill entries.
- Never prune, filter, or rename interface methods after backfill entries are recorded.
- Convert `unreachable!` into a proper diagnostic when a method may legitimately be absent.
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
- sys_op callee must resolve to a statically-known global func
- exhaustive realized-leaf template classification
- interface index {} is not an Object::Interface
- type-alias offset fits u32
- expected jump instruction at index {instruction_idx}
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/b7f9738691572772.
Report an issue: GitHub.