BoundaryML/baml · error

realized union-member template failed to substitute

Error message

realized union-member template failed to substitute: {e}

What it means

Panic in `ty_value_to_serde` when substituting a union member into a `TyTemplate` fails. Because the template is built from an already-realized `RealizedTy` it carries no frame refs or projections, so substitution is mathematically infallible; a failure means the type was not actually fully realized (e.g. it still contains unbound template variables or frame references).

Solutions

  1. Ensure types are fully realized (all template variables substituted) before calling ty_value_to_serde / json_to_string_typed.
  2. Upgrade bex_vm — this may be a realization-pass bug for union members.
  3. Reproduce with the smallest class/union definition and report it to baml_language maintainers.
  4. As a workaround, serialize the field with an explicit concrete type rather than through the generic union path.
Defensive patterns

Strategy: validation

Validate before calling

// Ensure union member types are fully realized before serialization:
fn fully_realized(ty: &RealizedTy) -> bool {
    !matches!(ty, RealizedTy::Var(_) | RealizedTy::FrameRef(_))
}

Try / catch

// Catchable only at the process level; validate realized types before ty_value_to_serde:
debug_assert!(fully_realized(&member_ty), "unrealized union member reached serde");

Prevention

When it happens

Trigger: Serializing a value whose union member type still contains unresolved template variables or frame references, reached via json_to_string_typed, ty_value_to_serde recursion, or serialize_class_instance on a class with generic/tEMPLATE union fields that were not fully substituted before serialization.

Common situations: Serializing instances of generic BAML classes with union-typed fields where the type realization pass missed a substitution step — typically after VM/typechecker upgrades or when embedding the type APIs directly.

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/0eae144601edf1c3. Report an issue: GitHub.

Appendix: source

Thrown at baml_language/crates/bex_vm/src/package_baml/json.rs:884

        )),

        RealizedTy::Union(members, _) => {
            // Select the first declared member that contains the runtime value,
            // using the same ordered, decidable membership relation as `is` and
            // typed match arms. Serialization then remains fully type-directed:
            // a class/media/uint8array member behaves exactly as it would outside
            // the union, and values outside every member fail the type contract.
            let member = members.iter().find(|member| {
                crate::type_match::value_matches_template(
                    vm,
                    value,
                    &TyTemplate::from((*member).clone()),
                    &[],
                )
                // A template built from a `RealizedTy` carries no frame refs
                // and no projections, so substitution cannot fail.
                .unwrap_or_else(|e| {
                    unreachable!("realized union-member template failed to substitute: {e}")
                })
            });
            match member {
                Some(member) => ty_value_to_serde(vm, value, member, path),
                None => Err(raise_serialize(
                    vm,
                    "value is not a member of the union",
                    path,
                    "union",
                )),
            }
        }

        RealizedTy::Resource { .. } | RealizedTy::PromptAst { .. } => Err(raise_serialize(
            vm,
            "cannot serialize opaque type",
            path,
            "opaque",

View on GitHub (pinned to bd85ce9dee)