BoundaryML/baml · error

field access on non-map/class at

Error message

field access on non-map/class at {:?}

What it means

For a field-access expression `base.field`, the interpreter only supports Map and Class base values; a missing field on those yields "missing field", but any other base type (list, string, scalar) throws "field access on non-map/class at {:?}". Dot access is reserved for structural values.

Solutions

  1. Check the base value's actual type and use the correct access form (index for lists, direct value for scalars)
  2. If expecting a class, ensure the expression constructs/returns that class (e.g. correct ClassConstructor call)
  3. For lists, index elements first, then access fields on the element
  4. Validate LLM/parse output shape so the value is a class/map as expected

Example fix

// before
let x = my_list.name // field access on non-map/class
// after
let x = my_list[0].name
Defensive patterns

Strategy: type-guard

Validate before calling

// Confirm the value supports field access before using dot syntax
function assertFieldAccess(v: unknown, field: string): void {
  if (v === null || typeof v !== "object" || Array.isArray(v))
    throw new Error(`Cannot access field '${field}' on ${Array.isArray(v) ? "list" : typeof v}`);
}

Type guard

function isStruct(v: unknown): v is Record<string, unknown> {
  return v !== null && typeof v === "object" && !Array.isArray(v);
}

Try / catch

try {
  return evalBaml(fieldExpr);
} catch (e) {
  if (String(e).includes("field access on non-map/class")) {
    throw new Error("Dot access requires a map or class — check the base value's type");
  }
  throw e;
}

Prevention

When it happens

Trigger: Using dot syntax on a value that evaluates to a list, string, int, bool, or null — e.g. `my_list.first`, `"text".length` — instead of a map or class instance.

Common situations: Assuming strings or lists have properties/methods like in other languages; accessing a field on what you thought was a class but the LLM/parse produced a scalar; chaining off a function call that returns the wrong type.

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/20dc7b45ef40013e. Report an issue: GitHub.

Appendix: source

Thrown at engine/baml-compiler/src/thir/interpret.rs:2055

                        base,
                        scopes,
                        thir,
                        run_llm_function,
                        watch_handler,
                        function_name,
                    )
                    .await?,
                )?;
                match b.clone() {
                    BamlValueWithMeta::Map(m, _) => {
                        let v = m.get(field).context("missing field")?;
                        EvalValue::Value(v.clone())
                    }
                    BamlValueWithMeta::Class(_, m, _) => {
                        let v = m.get(field).context("missing field")?;
                        EvalValue::Value(v.clone())
                    }
                    _ => bail!("field access on non-map/class at {:?}", meta.0),
                }
            }
            Expr::ClassConstructor { name, fields, meta } => {
                let mut field_map: BamlMap<String, BamlValueWithMeta<ExprMetadata>> =
                    BamlMap::new();

                for field in fields {
                    match field {
                        ClassConstructorField::Named { name, value } => {
                            field_map.insert(
                                name.clone(),
                                expect_value(
                                    evaluate_expr(
                                        value,
                                        scopes,
                                        thir,
                                        run_llm_function,
                                        watch_handler,

View on GitHub (pinned to bd85ce9dee)