BoundaryML/baml · error

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

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).

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)

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.