BoundaryML/baml · error

exhaustive realized-leaf template classification

Error message

exhaustive realized-leaf template classification

What it means

This panic fires in the compiler emitter while lowering a template/test expression whose right-hand side is a fully-realized leaf type (primitive, enum, alias, literal). The code intentionally calls `try_from` with `.expect` to assert that every such leaf can be converted to a `RealizedTy` for classification; hitting the panic means a new leaf variant was added to the type representation but not to the `TryFrom<&Ty> for RealizedTy` conversion, or a non-leaf type leaked into a code path reserved for realized leaves.

Source

Thrown at baml_language/crates/baml_compiler2_emit/src/emit.rs:3743

            | TyTemplate::Bool { .. }
            | TyTemplate::Null { .. }
            | TyTemplate::Uint8Array { .. }
            | TyTemplate::Enum(..)
            | TyTemplate::EnumVariant(..)
            | TyTemplate::RustType { .. }
            | TyTemplate::Type { .. }
            | TyTemplate::Resource { .. }
            | TyTemplate::PromptAst { .. }
            | TyTemplate::Void { .. }
            | TyTemplate::TypeAlias(..)
            | TyTemplate::Never { .. }) => {
                // A fully-realized leaf (primitive, enum, alias, literal, ...):
                // class-pointer identity for a `TypeAlias`, otherwise its type
                // tag when one exactly represents the test. Tagless leaves use
                // the canonical structural matcher instead of silently
                // compiling to false.
                let realized = <&RealizedTy>::try_from(other)
                    .expect("exhaustive realized-leaf template classification");
                if let RealizedTy::TypeAlias(tn, _) = realized {
                    if let Some(class_obj_idx) = self.class_object_index_for_type_name(tn) {
                        let c = self
                            .add_constant(ConstValue::Object(ObjectIndex::from_raw(class_obj_idx)));
                        let inst = self.emit(Instruction::IsType(c));
                        self.set_operand(inst, OperandMeta::Const(tn.display_name().to_string()));
                    } else {
                        emit_false(self);
                    }
                } else if let RealizedTy::Enum(tn, _) = realized {
                    // Enum-pointer identity: `is Color` tests the value's enum
                    // object, so it discriminates `Color` from `Status` - the
                    // shared `ENUM` type tag cannot. Falls back to constant-false
                    // if the enum object is absent (e.g. an unreferenced enum).
                    if let Some(enum_obj_idx) = self.enum_object_index_for_type_name(tn) {
                        let c = self
                            .add_constant(ConstValue::Object(ObjectIndex::from_raw(enum_obj_idx)));
                        let inst = self.emit(Instruction::IsType(c));

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Extend the `TryFrom<&Ty> for RealizedTy` implementation to handle the offending leaf variant
  2. Verify the operand reaching emit.rs:3743 is actually a realized leaf; if it carries holes, route it to the structural-matcher path instead
  3. Check recent type-system changes for new `Ty` variants missing from the conversion
  4. Run the template/type-test compiler tests to confirm classification coverage

Example fix

// before
let realized = <&RealizedTy>::try_from(other)
    .expect("exhaustive realized-leaf template classification");
// after: handle new variant in the conversion
impl TryFrom<&Ty> for RealizedTy {
    fn try_from(t: &Ty) -> Result<Self, Self::Error> {
        // ...
        Ty::NewLeafKind(x) => Ok(RealizedTy::NewLeafKind(x.clone())),
        // ...
    }
}
Defensive patterns

Strategy: type-guard

Validate before calling

fn is_realized_leaf(t: &Ty) -> bool {
    matches!(
        t,
        Ty::Primitive(_) | Ty::Enum(_) | Ty::Alias(_, _) | Ty::Literal(_) | Ty::TypeAlias(_, _)
    )
}

Type guard

fn as_realized(t: &Ty) -> Option<&RealizedTy> {
    <&RealizedTy>::try_from(t).ok()
}

Try / catch

// Rust panics are not catchable with ?; use std::panic::catch_unwind only at a process boundary
let result = std::panic::catch_unwind(|| emit_template_test(node));
match result {
    Ok(Ok(out)) => out,
    _ => report_internal_error("template classification failed"),
}

Prevention

When it happens

Trigger: Compiling a `is`/type-test template whose operand is a leaf type that the `RealizedTy::try_from` conversion does not recognize — typically after adding a new `Ty` variant without updating the conversion, or a structural/holes-carrying type reaching the leaf path.

Common situations: Contributors to the BAML compiler adding new type forms (new primitive kinds, literal variants, or alias wrappers) without extending `RealizedTy`; refactors that let non-realized (hole-carrying) types reach the template-classification branch.

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