BoundaryML/baml · error

field access must be on classes, but expr `{}` got: {other:?

Error message

field access must be on classes, but expr `{}` got: {other:?}

What it means

Panic when the base of a field-access expression resolves to a type that is not a class (and not an enum handled earlier). Field access in this codegen is only defined for class-typed bases; any other resolved type reaches the `other =>` catch-all, which panics with the base expression's dumped source and its type. Type checking should have rejected non-class field accesses before codegen.

Source

Thrown at engine/baml-compiler/src/codegen.rs:1200

                    Some(TypeIR::Class {
                        name: class_name, ..
                    }) => {
                        let Some(_class_index) = self.globals.get(class_name) else {
                            panic!("undefined class: {class_name}");
                        };

                        let Some(resolved_fields) = self.classes.get(class_name) else {
                            panic!("undefined class: {class_name}");
                        };

                        let Some(&field_index) = resolved_fields.get(field) else {
                            panic!("undefined field: {class_name}.{field}");
                        };

                        self.emit(Instruction::LoadField(field_index));
                    }

                    other => panic!(
                        "field access must be on classes, but expr `{}` got: {other:?}",
                        base.dump_str()
                    ),
                }
            }

            thir::Expr::Var(name, _) => {
                if let Some(&index) = self.locals.get(name) {
                    self.emit(Instruction::LoadVar(index));
                } else if let Some(class) = self.globals.get(name) {
                    self.emit(Instruction::LoadGlobal(*class));
                } else {
                    panic!("undefined variable: {name}");
                }
            }

            thir::Expr::List(elements, _) => {
                for element in elements {

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Use bracket indexing (`base["key"]`) for map access instead of dot access
  2. Unwrap optional values before accessing fields
  3. Ensure the base expression actually evaluates to a class instance
  4. If the base is a valid class, report a compiler bug: resolved type metadata is wrong at codegen

Example fix

// before
let v = myMap.key
// after
let v = myMap["key"]
Defensive patterns

Strategy: type-guard

Validate before calling

// Only dot-access fields on class-typed bases
match base_type {
    TypeIR::Class { .. } => { /* field access allowed */ }
    TypeIR::Map(..) => return Err("use [\"key\"] indexing for maps"),
    other => return Err(format!("cannot field-access {other:?}")),
}

Type guard

fn is_class_typed(t: &TypeIR) -> bool {
    matches!(t, TypeIR::Class { .. })
}

Prevention

When it happens

Trigger: Compiling `Expr::FieldAccess` whose base resolves to a non-class, non-enum type — e.g. `.field` on a string, int, list, or optional value; or the base type metadata is missing/misresolved.

Common situations: Dot-accessing into a map or list instead of using indexing; accessing fields on primitives (e.g. `str.length` style not supported); optional bases that were not unwrapped before field access.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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