apache/iceberg · error · IllegalArgumentException
Cannot convert nested accessor to position
Error message
Cannot convert nested accessor to position
What it means
Accessors.toPosition() converts an accessor to an integer position only when it is a PositionAccessor. Nested accessors (e.g. accessing a field inside a nested struct) cannot be reduced to a single top-level position, so this IllegalArgumentException is thrown. It guards against misuse of the accessor API.
Source
Thrown at api/src/main/java/org/apache/iceberg/Accessors.java:51
* |-- a: struct (nullable = false)
* | |-- b: struct (nullable = false)
* | | -- c: string (containsNull = false)
* </pre>
*
* Then we will use Position3Accessor to access nested field 'c'. It can be accessed like this:
* {@code row.get(p0, StructLike.class).get(p1, StructLike.class).get(p2, javaClass)}. Commonly,
* Nested fields with depth=1 or 2 or 3 are the fields that will be accessed frequently, so this
* optimization will help to access this kind of schema. For schema whose depth is deeper than 3,
* then we will use the {@link WrappedPositionAccessor} to access recursively.
*/
public class Accessors {
private Accessors() {}
public static Integer toPosition(Accessor<StructLike> accessor) {
if (accessor instanceof PositionAccessor) {
return ((PositionAccessor) accessor).position();
}
throw new IllegalArgumentException("Cannot convert nested accessor to position");
}
static Map<Integer, Accessor<StructLike>> forSchema(Schema schema) {
return TypeUtil.visit(schema, new BuildPositionAccessors());
}
private static class PositionAccessor implements Accessor<StructLike> {
private final int position;
private final Type type;
private final Class<?> javaClass;
PositionAccessor(int pos, Type type) {
this.position = pos;
this.type = type;
this.javaClass = type.typeId().javaClass();
}
@OverrideView on GitHub (pinned to 86d9c8fc54)
Solutions
- Only call toPosition() for top-level (non-nested) field accessors; check instanceof Accessors.PositionAccessor first.
- For nested fields, navigate the accessor chain yourself instead of asking for a single position.
- If your schema must be flat, flatten it (e.g. schema case-aware access via projected schema) before building accessors.
Example fix
// before
Integer pos = Accessors.toPosition(accessor);
// after
if (accessor instanceof Accessors.PositionAccessor) {
Integer pos = ((Accessors.PositionAccessor) accessor).position();
} else {
// handle nested accessor path
} Defensive patterns
Strategy: type-guard
Type guard
if (accessor instanceof Accessors.PositionAccessor) {
int pos = ((Accessors.PositionAccessor) accessor).position();
} else {
// nested accessor: walk its nested path instead of toPosition()
} Try / catch
try {
Integer pos = Accessors.toPosition(accessor);
} catch (IllegalArgumentException e) {
// fall back to nested-accessor handling
} Prevention
- Check instanceof PositionAccessor before calling toPosition().
- Design code paths over accessors to handle nested struct fields.
- Add tests with nested schemas to catch non-positional accessors.
When it happens
Trigger: Passing an accessor obtained for a nested field (produced by visiting a schema with nested struct fields) into Accessors.toPosition(), e.g. when code assumes all accessors are positional.
Common situations: Writing generic code over schema accessors that handles flat schemas but encounters nested types (struct-in-struct, list of structs); older code paths after schemas gained nested fields.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Invalid default value for %s: %s (must be null)
- Unsorted order ID must be 0
- Default values are not supported
- UnsupportedOperationException
- Field + name + not found in source schema
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/80f9f8f1a03c277c.
Report an issue: GitHub.