BoundaryML/baml · error
interface frame starts with Self
Error message
interface frame starts with Self
What it means
While building packages, the compiler fetches an interface's frame parameters via `lower::interface_frame` and `.expect`s that the first parameter is `Self`. The panic means `interface_frame` returned an empty parameter list (or a list not starting with Self), so the interface lacks its implicit Self parameter.
Source
Thrown at baml_language/crates/baml_compiler2_emit/src/lib.rs:800
let iface_tn = spelling.wire(&qualify_def(
db,
Definition::Interface(iface_loc),
&iface_data.name,
));
if !iface_data.fields.is_empty() {
iface_field_decls
.entry(iface_tn.clone())
.or_insert_with(|| iface_data.fields.iter().map(|f| f.name.clone()).collect());
}
if !iface_data.associated_types.is_empty() {
iface_assoc_decls
.entry(iface_tn.clone())
.or_insert_with(|| {
let frame_params =
baml_compiler2_hir_ty::lower::interface_frame(db, iface_loc);
let self_param = frame_params
.first()
.expect("interface frame starts with Self")
.clone();
(
self_param,
baml_compiler2_hir_ty::lower::interface_declared_params(db, iface_loc),
iface_data
.associated_types
.iter()
.map(|assoc| {
(
assoc.name.clone(),
baml_compiler2_hir_ty::interfaces::
interface_associated_type_default(
db,
iface_loc,
assoc.name.clone(),
)
.map(|(ty, _decl_site_diags)| ty),
)View on GitHub (pinned to bd85ce9dee)
Solutions
- Fix the lowering pass so `interface_frame` always yields Self as the first parameter
- Verify `iface_loc` refers to the correct interface declaration (not a stale or wrong node)
- Clear incremental/cached HIR data and rebuild
- Add a defensive error path reporting which interface lacks Self instead of panicking
Defensive patterns
Strategy: validation
Validate before calling
let frame_params = lower::interface_frame(db, iface_loc);
if frame_params.first().map(|p| p.is_self()) != Some(true) {
return Err(CompilerBug::InterfaceMissingSelf(iface_tn.clone()));
} Type guard
fn frame_starts_with_self(params: &[Param]) -> bool {
params.first().map(|p| p.is_self()).unwrap_or(false)
} Try / catch
std::panic::catch_unwind(|| build_packages(db))
.unwrap_or_else(|_| report_compiler_bug("interface frame missing Self")); Prevention
- Ensure the interface lowering pass always inserts Self as the first frame parameter
- Validate iface_loc resolution against the current HIR, not cached indices
- Add a lowering round-trip test asserting Self presence for every interface fixture
When it happens
Trigger: Calling `build_packages` on an interface whose HIR frame has no leading Self parameter — e.g., the interface was built by a lowering pass that dropped the Self parameter, or the lookup `iface_loc` points at the wrong declaration node.
Common situations: Regressions in the HIR lowering for interfaces; malformed or hand-edited intermediate representations; resolving an interface location from a stale/cached index.
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
- interface `{iface_wire}` declares a non-runtime type: {e:?}
- interface `{iface_wire}` declares a non-runtime constraint:
- split_interface matched an interface
- sys_op callee must resolve to a statically-known global func
- expected jump instruction at index {instruction_idx}
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/67e0c0f6638a4738.
Report an issue: GitHub.