apache/flink · error · IndexOutOfBoundsException

Tuple position is out of range: {f}

Error message

Tuple position is out of range: {f}

What it means

Thrown by Keys.rangeCheckFields as an IndexOutOfBoundsException when a field index in the supplied positions array is negative or exceeds maxAllowedField (typically arity-1). This validates positional key arrays for tuple types before they are committed.

Source

Thrown at flink-core/src/main/java/org/apache/flink/api/common/operators/Keys.java:504

    // --------------------------------------------------------------------------------------------
    //  Utilities
    // --------------------------------------------------------------------------------------------

    private static int[] createIncrIntArray(int numKeys) {
        int[] keyFields = new int[numKeys];
        for (int i = 0; i < numKeys; i++) {
            keyFields[i] = i;
        }
        return keyFields;
    }

    @VisibleForTesting
    static void rangeCheckFields(int[] fields, int maxAllowedField) {

        for (int f : fields) {
            if (f < 0 || f > maxAllowedField) {
                throw new IndexOutOfBoundsException("Tuple position is out of range: " + f);
            }
        }
    }

    public static class IncompatibleKeysException extends Exception {
        private static final long serialVersionUID = 1L;
        public static final String SIZE_MISMATCH_MESSAGE =
                "The number of specified keys is different.";

        public IncompatibleKeysException(String message) {
            super(message);
        }

        public IncompatibleKeysException(
                TypeInformation<?> typeInformation, TypeInformation<?> typeInformation2) {
            super(typeInformation + " and " + typeInformation2 + " are not compatible");
        }
    }

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Validate each element of the positions array against [0, arity-1] before constructing ExpressionKeys.
  2. Derive positions from type.getFieldNames() or type.getArity() rather than hardcoding.
  3. Guard against negative values from untrusted input.

Example fix

// before
int[] positions = {0, 5};
new Keys.ExpressionKeys(positions, tupleTypeInfo);  // arity 3 → 5 out of range

// after
int[] positions = {0, 5};
for (int p : positions) {
    if (p < 0 || p >= tupleTypeInfo.getArity()) {
        throw new IllegalArgumentException("bad position " + p);
    }
}
new Keys.ExpressionKeys(positions, tupleTypeInfo);
Defensive patterns

Strategy: validation

Validate before calling

int maxAllowed = type.getArity() - 1;
for (int f : fields) {
    if (f < 0 || f > maxAllowed) {
        throw new IllegalArgumentException(
            "Field " + f + " out of range [0," + maxAllowed + "]");
    }
}

Try / catch

try {
    Keys.rangeCheckFields(positions, arity - 1);
} catch (IndexOutOfBoundsException e) {
    throw new IllegalArgumentException("Invalid key positions", e);
}

Prevention

When it happens

Trigger: Constructing ExpressionKeys(new int[]{0, 99}, tupleTypeInfo) where 99 exceeds the tuple arity. Passing an int[] with a negative value to keyBy or grouping APIs.

Common situations: Building key position arrays from external config or user input without bounds checking. Off-by-one when maxAllowedField is computed as arity-1 but caller uses arity.

Related errors


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