{"record":{"id":"b2eb8d9bd620ba32","repo":"BoundaryML/baml","slug":"interface-iface-wire-declares-a-non-runtime-type-e","errorCode":null,"errorMessage":"interface `{iface_wire}` declares a non-runtime type: {e:?}","messagePattern":"interface `(.+?)` declares a non-runtime type: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"baml_language/crates/baml_compiler2_emit/src/lib.rs","lineNumber":134,"sourceCode":"        .with_frame(interface_frame_params.clone())\n        .with_bounds(baml_compiler2_hir_ty::lower::interface_scope_bounds(\n            db, iface_loc,\n        ));\n\n    // Lower a type ref in `ctx` and narrow to a runtime type. Diagnostics are\n    // not collected: emit only runs on a checked program, so the declaration\n    // is already validated. `lower_to_runtime` rejects only the\n    // error-recovery sentinels, which a checked program cannot contain, so a\n    // failure means a compiler bug and must not be papered over by dropping\n    // the entry (that would renumber positional arguments).\n    let lower_rt = |ctx: &baml_compiler2_hir_ty::lower::LowerCtx<'_>,\n                    store: &TypeRefStore,\n                    id: TypeRefId|\n     -> bex_vm_types::RuntimeTy {\n        let ty = baml_compiler2_hir_ty::lower::reject_holes(&ctx.lower_type_ref(store, id));\n        let runtime = baml_type::lower_to_runtime(&ty, resolved.aliases)\n            .unwrap_or_else(|e| {\n                unreachable!(\"interface `{iface_wire}` declares a non-runtime type: {e:?}\")\n            })\n            .map_heads(&mut |decl| resolved.wire(decl));\n        bex_vm_types::anchor_runtime_ty(&runtime)\n    };\n    // Lower an interface bound / `requires` target / associated-type bound.\n    // These are constraint heads: hir keeps written pins only (no eager\n    // default realization). A target that is not an interface was rejected\n    // upstream (E0145 / E0133) and yields `None`.\n    let lower_iface = |ctx: &baml_compiler2_hir_ty::lower::LowerCtx<'_>,\n                       store: &TypeRefStore,\n                       id: TypeRefId|\n     -> Option<bex_vm_types::RuntimeInterface> {\n        // ConstraintHead, per the contract above: the default (existential)\n        // position eagerly realizes omitted associated defaults and fills\n        // the rest with Error sentinels — a bound like `type A extends\n        // Iface` with unpinned associated types would panic `to_runtime`.\n        let lowered = baml_compiler2_hir_ty::lower::reject_holes(&ctx.lower_type_ref_at(\n            store,","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/baml_language/crates/baml_compiler2_emit/src/lib.rs#L116-L152","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"// before\ninterface Foo {\n  fn op(cb: fn(int) -> string)\n}\n// after: use a runtime-representable shape\ninterface Foo {\n  fn op(cb: (int) => string)  // or whatever callable type the runtime supports\n}","handlingStrategy":"validation","validationCode":"// before declaring the interface, ensure member types are runtime-representable\nfn interface_types_are_runtime_representable(iface: &InterfaceDecl) -> Result<(), TypeError> {\n    iface.fields.iter().chain(iface.methods.iter())\n        .map(|m| lower_to_runtime(&lower(m.ty)?, &aliases))\n        .collect::<Option<Vec<_>>>()\n        .ok_or(TypeError::NonRuntimeTypeInInterface(iface.name.clone()))\n}","typeGuard":null,"tryCatchPattern":"std::panic::catch_unwind(|| build_interface_def(resolved, store))\n    .unwrap_or_else(|_| report_compiler_bug(\"interface has non-runtime type\"));","preventionTips":["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"],"tags":["compiler","rust","panic","interfaces","type-lowering"],"backgroundTag":"internal-invariant-violation","analyzedSha":"bd85ce9dee1463ff04d27efd20531013a4ff46c1","analyzedAt":"2026-09-12T03:38:25.718Z","contentChangedAt":"2026-09-12T03:38:25.718Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}