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
- Ensure types are fully realized (all template variables substituted) before calling ty_value_to_serde / json_to_string_typed.
- Upgrade bex_vm — this may be a realization-pass bug for union members.
- Reproduce with the smallest class/union definition and report it to baml_language maintainers.
- 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
- Run the full type-realization/substitution pass before serializing generic classes.
- Avoid serializing values carrying unresolved template variables.
- Keep the typechecker and VM on matching versions.
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
- PackageInterface artifact serialization into Vec is infallib
- generic arity fits u32
- honest interface fragment for `{}` failed to serialize: {e}
- 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/0eae144601edf1c3.
Report an issue: GitHub.