BoundaryML/baml · error
generic arity fits u32
Error message
generic arity fits u32
What it means
When building an impl frame, the compiler converts the impl's declared generic parameter count to `u32` with `.expect("generic arity fits u32")` to generate `TyTemplate::TypeArgRef` slots. The panic means an impl block declares more than `u32::MAX` generic parameters — practically only reachable via an arity-computation bug, since real declarations cannot have 4 billion generics.
Source
Thrown at baml_language/crates/baml_compiler2_emit/src/lib.rs:1050
_ => unreachable!("split_interface matched an interface"),
};
complete_interface_assoc(
&mut interface_assoc,
&iface_tn,
&iface_arg_tys,
&for_ty,
&impl_params,
resolved,
);
// The constraint set was lowered (and fail-closed gated) inside
// `impl_rule_target`, so the bake, the decompose attribution,
// and the rule's `ImplCoherenceKey` all carry the identical
// canonicalized bounds.
// A block's own method is compiled against the owner frame — the
// impl's declared generics, which for an in-class block ARE the
// class's.
let impl_frame: Vec<bex_vm_types::TyTemplate> = (0..u32::try_from(impl_params.len())
.expect("generic arity fits u32"))
.map(bex_vm_types::TyTemplate::TypeArgRef)
.collect();
let Some(interface_head) = interface_indices
.get(&iface_tn)
.copied()
.map(ObjectIndex::from_raw)
else {
continue;
};
let mut methods = indexmap::IndexMap::new();
for &m in &block.methods {
let method_name = function_data(db, m).name.clone();
// An unindexed body has a `$compiler_intrinsic` /
// `$await_any` body Pass 4 never pools — drop just that
// method (losing a dispatch, never adding a wrong one). The
// stdlib only uses those bodies on free functions, so this is
// unreachable today; the debug_assert pins the convention.
// TODO: reject intrinsic/await-any bodies inside impl blocksView on GitHub (pinned to bd85ce9dee)
Solutions
- Audit how `impl_params` is collected for duplication or runaway expansion
- Deduplicate the generic parameter list before frame construction
- If genuinely large arities are expected, widen the field or cap with a proper diagnostic
Example fix
// before
u32::try_from(impl_params.len()).expect("generic arity fits u32")
// after
u32::try_from(impl_params.len())
.map_err(|_| EmitError::TooManyGenerics(impl_params.len()))? Defensive patterns
Strategy: validation
Validate before calling
if impl_params.len() > u32::MAX as usize {
return Err(CompilerBug::GenericArityOverflow(impl_params.len()));
} Type guard
fn fits_u32(n: usize) -> Option<u32> {
u32::try_from(n).ok()
} Try / catch
std::panic::catch_unwind(|| build_packages(db))
.unwrap_or_else(|_| report_compiler_bug("generic arity overflow")); Prevention
- Deduplicate impl_params before frame construction to catch collection bugs
- Cap declared generic arity at parse time
- Add a test that merging class and impl generics does not duplicate parameters
When it happens
Trigger: `impl_params.len()` overflowing u32 during `build_packages` frame construction — caused by duplicated or recursively expanded parameter lists rather than a genuine huge arity.
Common situations: Lowering bugs that duplicate generic parameters when merging class and impl generics; pathological generated code; infinite recursion in parameter collection that inflated the list.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- ntypeargs fits u16
- class field count fits u32
- sys_op callee must resolve to a statically-known global func
- expected jump instruction at index {instruction_idx}
- exhaustive realized-leaf template classification
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/a688fdb296e21b39.
Report an issue: GitHub.