BoundaryML/baml · error

class offset fits u32

Error message

class offset fits u32

What it means

A Rust `expect("class offset fits u32")` panic in baml_compiler2_emit's local-unit packing code. When distributing pooled objects into per-unit local pools, the next class offset (`units[u].classes.len()`) is converted to `u32`; the compiler assumes every unit holds fewer than 2^32 classes. Exceeding that means the object pool grew to an absurd size, so the library panics rather than silently truncating offsets.

Source

Thrown at baml_language/crates/baml_compiler2_emit/src/lib.rs:2435

                referenced_names: refs
                    .map(|r| r.names.iter().cloned().collect())
                    .unwrap_or_default(),
                bakes_type_layout: refs.is_some_and(|r| r.bakes_type_layout),
                ..CompilationUnit::default()
            }
        })
        .collect();
    // Per pool object: its LocalRef within its owning unit (bucket + offset).
    let mut obj_localref: Vec<LocalRef> = Vec::with_capacity(tail_start - prefix_objects);
    for (offset, kind) in obj_kind.iter().enumerate() {
        let idx = prefix_objects + offset;
        let u = obj_owner[idx];
        let obj = program.objects[ObjectIndex::from_raw(idx)].clone();
        let local_ref = match kind {
            PoolObjKind::Class => {
                let off = units[u].classes.len();
                units[u].classes.push(obj);
                LocalRef::Class(u32::try_from(off).expect("class offset fits u32"))
            }
            PoolObjKind::Enum => {
                let off = units[u].enums.len();
                units[u].enums.push(obj);
                LocalRef::Enum(u32::try_from(off).expect("enum offset fits u32"))
            }
            PoolObjKind::Interface => {
                let off = units[u].interfaces.len();
                units[u].interfaces.push(obj);
                LocalRef::Interface(u32::try_from(off).expect("interface offset fits u32"))
            }
            PoolObjKind::TypeAlias => {
                let off = units[u].type_alias_objects.len();
                units[u].type_alias_objects.push(obj);
                LocalRef::TypeAlias(u32::try_from(off).expect("type-alias offset fits u32"))
            }
            PoolObjKind::NamedFn(_) | PoolObjKind::CodeAnon => {
                let off = units[u].code.len();

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Treat this as a symptom of a duplicate-push/dedup bug: audit the pooling loop to ensure each pooled class is assigned to a unit at most once.
  2. Add a guard that fails compilation with a clear diagnostic before the pool exceeds u32 capacity.
  3. If genuinely enormous inputs must be supported, widen the offset type to `u64`/`usize` in `LocalRef` and the unit serialization format.
  4. Check the number of distinct classes in the offending input; a legitimate program cannot need billions, so inspect for generated/pathological input.

Example fix

// before
let off = units[u].classes.len();
units[u].classes.push(obj);
LocalRef::Class(u32::try_from(off).expect("class offset fits u32"))
// after
if units[u].classes.len() > u32::MAX as usize {
    return Err(EmitError::UnitOverflow { unit: u, kind: "class" });
}
let off = units[u].classes.len();
units[u].classes.push(obj);
LocalRef::Class(off as u32)
Defensive patterns

Strategy: validation

Validate before calling

// Not applicable to BAML users. Embedders can pre-check pool size before packing:
fn class_pool_within_u32(program: &Program) -> bool {
    program.objects.iter().filter(|o| matches!(o, Object::Class(_))).count() < u32::MAX as usize
}

Try / catch

// Panics are not catchable from BAML user code. Embedders can isolate compilation:
let result = std::panic::catch_unwind(|| compile(&source));
if result.is_err() {
    report_internal_compiler_error();
}

Prevention

When it happens

Trigger: Triggered while assigning `PoolObjKind::Class` objects to local units when `units[u].classes.len()` exceeds `u32::MAX` (4,294,967,295) — only possible with an enormous or runaway/duplicated class pool.

Common situations: Effectively unreachable in real BAML projects; seen only in fuzzing or compiler-dev scenarios such as a pool-dedup bug pushing the same classes repeatedly, or synthetic generated inputs with billions of classes.

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


AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12). Data as JSON: /api/errors/40eaf97c3ac78f95. Report an issue: GitHub.