apache/flink · error · IllegalArgumentException

Accessing a field by name is not supported in position-based

Error message

Accessing a field by name is not supported in position-based field mode.

What it means

Mirror of the positional case: getField(String name) requires name-based mode. If the row was created position-based (Row.of(...), Row.ofKind(...)) then fieldByName and positionByName are both null, and any by-name access is rejected with this IllegalArgumentException because no name information exists.

Source

Thrown at flink-core/src/main/java/org/apache/flink/types/Row.java:297

     *
     * <p>Note: The row must operate in name-based field mode.
     *
     * @param name the name of the field or null if not set previously
     * @return the field's content
     */
    public @Nullable Object getField(String name) {
        if (fieldByName != null) {
            return fieldByName.get(name);
        } else if (positionByName != null) {
            final Integer pos = positionByName.get(name);
            if (pos == null) {
                throw new IllegalArgumentException(
                        String.format("Unknown field name '%s' for mapping to a position.", name));
            }
            assert fieldByPosition != null;
            return fieldByPosition[pos];
        } else {
            throw new IllegalArgumentException(
                    "Accessing a field by name is not supported in position-based field mode.");
        }
    }

    /**
     * Returns the field's content using the specified field name.
     *
     * <p>Note: The row must operate in name-based field mode.
     *
     * <p>This method avoids a lot of manual casting in the user implementation.
     *
     * @param name the name of the field, set previously
     * @return the field's content
     */
    @SuppressWarnings("unchecked")
    public <T> T getFieldAs(String name) {
        return (T) getField(name);
    }

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Use getField(int pos) on position-based rows
  2. Create the row with Row.withNames() if named access is required
  3. Convert at the boundary: build a hybrid row by attaching names (Row.withPositions + setField names) before handing it to name-based consumers

Example fix

// before
Row row = Row.of(42, "alice");
Object v = row.getField("id"); // throws

// after
Object v = row.getField(0);
Defensive patterns

Strategy: type-guard

Validate before calling

if (row.getFieldNames(true) == null) {
    throw new IllegalArgumentException("Row has no field names; use positional access");
}

Type guard

static boolean isNameBased(Row row) {
    return row.getFieldNames(true) != null;
}

Try / catch

catch (IllegalArgumentException e) { throw new IllegalStateException("Row mode mismatch; expected name-based", e); }

Prevention

When it happens

Trigger: Calling getField(String) / getFieldAs(String, Class) on a Row created with Row.of(...) or Row.ofKind(...) where no field names were ever attached.

Common situations: Table/SQL-derived code assuming named access receiving raw position-based rows from DataStream sources or UDF output; refactoring a row creation site from withNames() to of() without updating readers.

Related errors


AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14). Data as JSON: /api/errors/a11a565d32142fd9. Report an issue: GitHub.