BoundaryML/baml · error
interface `{iface_wire}` declares a non-runtime type: {e:?}
Error message
interface `{iface_wire}` declares a non-runtime type: {e:?} What it means
While building an interface definition, each declared type is lowered to HIR, hole-checked, then converted to a runtime type via `baml_type::lower_to_runtime`. A `None`/`Err` result means the interface declares a type with no runtime representation (e.g., a purely compile-time constraint type such as a bare type-variable or function type). The code treats that as impossible for a valid interface and calls `unreachable!`, crashing with this message.
Source
Thrown at baml_language/crates/baml_compiler2_emit/src/lib.rs:134
.with_frame(interface_frame_params.clone())
.with_bounds(baml_compiler2_hir_ty::lower::interface_scope_bounds(
db, iface_loc,
));
// Lower a type ref in `ctx` and narrow to a runtime type. Diagnostics are
// not collected: emit only runs on a checked program, so the declaration
// is already validated. `lower_to_runtime` rejects only the
// error-recovery sentinels, which a checked program cannot contain, so a
// failure means a compiler bug and must not be papered over by dropping
// the entry (that would renumber positional arguments).
let lower_rt = |ctx: &baml_compiler2_hir_ty::lower::LowerCtx<'_>,
store: &TypeRefStore,
id: TypeRefId|
-> bex_vm_types::RuntimeTy {
let ty = baml_compiler2_hir_ty::lower::reject_holes(&ctx.lower_type_ref(store, id));
let runtime = baml_type::lower_to_runtime(&ty, resolved.aliases)
.unwrap_or_else(|e| {
unreachable!("interface `{iface_wire}` declares a non-runtime type: {e:?}")
})
.map_heads(&mut |decl| resolved.wire(decl));
bex_vm_types::anchor_runtime_ty(&runtime)
};
// Lower an interface bound / `requires` target / associated-type bound.
// These are constraint heads: hir keeps written pins only (no eager
// default realization). A target that is not an interface was rejected
// upstream (E0145 / E0133) and yields `None`.
let lower_iface = |ctx: &baml_compiler2_hir_ty::lower::LowerCtx<'_>,
store: &TypeRefStore,
id: TypeRefId|
-> Option<bex_vm_types::RuntimeInterface> {
// ConstraintHead, per the contract above: the default (existential)
// position eagerly realizes omitted associated defaults and fills
// the rest with Error sentinels — a bound like `type A extends
// Iface` with unpinned associated types would panic `to_runtime`.
let lowered = baml_compiler2_hir_ty::lower::reject_holes(&ctx.lower_type_ref_at(
store,View on GitHub (pinned to bd85ce9dee)
Solutions
- Change the interface declaration so every member type has a concrete runtime representation (replace type variables/function types with supported types)
- Ensure generic parameters are declared on the interface so heads resolve to runtime types
- If the type should be representable, fix `baml_type::lower_to_runtime` to handle it
- Replace the `unreachable!` with a proper diagnostic error if a user-facing case is found
Example fix
// before
interface Foo {
fn op(cb: fn(int) -> string)
}
// after: use a runtime-representable shape
interface Foo {
fn op(cb: (int) => string) // or whatever callable type the runtime supports
} Defensive patterns
Strategy: validation
Validate before calling
// before declaring the interface, ensure member types are runtime-representable
fn interface_types_are_runtime_representable(iface: &InterfaceDecl) -> Result<(), TypeError> {
iface.fields.iter().chain(iface.methods.iter())
.map(|m| lower_to_runtime(&lower(m.ty)?, &aliases))
.collect::<Option<Vec<_>>>()
.ok_or(TypeError::NonRuntimeTypeInInterface(iface.name.clone()))
} Try / catch
std::panic::catch_unwind(|| build_interface_def(resolved, store))
.unwrap_or_else(|_| report_compiler_bug("interface has non-runtime type")); Prevention
- Do not put function types or bare type variables in interface members without generic declarations
- Declare generic parameters explicitly so heads resolve to runtime types
- Extend hole-checking to reject constraint-only types before runtime lowering
When it happens
Trigger: Declaring an `interface` whose member/associated type lowers to a non-runtime-representable type (e.g., an unresolved generic head, a function type, or a type with holes that passed hole-checking but cannot be lowered to a runtime type).
Common situations: Writing an interface with an exotic type annotation (generics misuse, function-typed fields) that the type checker admits but the runtime lowering rejects; compiler regressions in `lower_to_runtime` after adding new `Ty` variants.
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 constraint:
- interface frame starts with Self
- 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/b2eb8d9bd620ba32.
Report an issue: GitHub.