BoundaryML/baml · error
Package.classes only contains class pointers
Error message
Package.classes only contains class pointers
What it means
`package_class_type` builds a reflected type for a class obtained from a package's `Package.classes` list. The `unreachable!` fires if the stored pointer does not point to an `Object::Class` — meaning the package's classes table was corrupted or populated with a non-class object. This is a hard internal invariant: the library only ever stores class pointers there.
Source
Thrown at baml_language/crates/bex_vm/src/package_reflect/reflect.rs:287
interface: &Interface,
member: &baml_type::Name,
fuel: u32,
) -> baml_type::normalize::ProjectionStep<bex_vm_types::TypeHead> {
TypeContext::project(self.vm, base, interface, member, fuel)
}
}
fn package_class_type(vm: &mut BexVm, runtime_type: Option<HeapPtr>, class_ptr: HeapPtr) -> Value {
if let Some(runtime_type) = runtime_type {
let ty_value = Value::object(runtime_type);
return super::type_kinds::alloc_kind_view(
vm,
baml_type::type_kind::TypeKind::Class,
ty_value,
);
}
let Object::Class(class) = vm.get_object(class_ptr) else {
unreachable!("Package.classes only contains class pointers")
};
let ty = RealizedTy::Class(
bex_vm_types::TypeHead::new(class_ptr, class.type_tag),
Box::new([]),
class.ty_attr.clone(),
);
let ty_value = Value::object(vm.tlab.alloc_type(TypeValue::new(ty)));
super::type_kinds::alloc_kind_view(vm, baml_type::type_kind::TypeKind::Class, ty_value)
}
fn package_enum_type(vm: &mut BexVm, runtime_type: Option<HeapPtr>, enum_ptr: HeapPtr) -> Value {
if let Some(runtime_type) = runtime_type {
let ty_value = Value::object(runtime_type);
return super::type_kinds::alloc_kind_view(
vm,
baml_type::type_kind::TypeKind::Enum,
ty_value,
);View on GitHub (pinned to bd85ce9dee)
Solutions
- Audit the GC/forwarding path: ensure class pointers in Package.classes are updated on object moves before reflection reads them.
- Verify no unsafe code writes non-class objects into the package's classes table.
- Reproduce with the GC test suite and check whether the pointer was swept/forwarded correctly (see dynamic_dispatch_entries tests).
- If hit in a test, follow forwarding entries for stored pointers before calling reflection APIs.
Example fix
// before: using a stale pointer captured before a GC let class_ptr = package.classes(vm)[0]; sweep_and_forward(); let ty = package_class_type(vm, class_ptr); // panics: pointer moved // after: re-read pointers after the sweep, or follow forwarding let class_ptr = forwarding.get(&class_ptr).copied().unwrap_or(class_ptr); let ty = package_class_type(vm, class_ptr);
Defensive patterns
Strategy: validation
Validate before calling
// verify a class pointer is still valid after GC before reflection
fn is_class(vm: &BexVm, p: HeapPtr) -> bool { matches!(vm.get_object(p), Object::Class(_)) } Type guard
fn as_class<'a>(vm: &'a BexVm, p: HeapPtr) -> Option<&'a Class> {
match vm.get_object(p) { Object::Class(c) => Some(c), _ => None }
} Prevention
- Re-read pointers from Package.classes after any GC cycle instead of caching them.
- Keep GC forwarding tests green so package-stored pointers always follow relocations.
- Avoid unsafe writes into package tables; use the loader's typed insertion APIs only.
When it happens
Trigger: Calling `package_class_type` (directly or via `get_class`/`classes`) when a package's class slot holds a moved/stale/dropped heap pointer whose memory now holds a different object variant — typically after a GC forwarding bug or manual pointer manipulation.
Common situations: GC bugs that forward class pointers incorrectly; tests that read class pointers after sweeping without following forwarding entries; heap corruption from unsafe code that writes non-class objects into the package tables.
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
- Package.enums only contains enum pointers
- live owner must be forwarded
- Package.current call site names a loaded package
- no-color diagnostics do not invoke the message highlighter
- rendering without a message highlighter cannot fail semantic
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/98efb763c2519ea1.
Report an issue: GitHub.