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
- Validate each element of the positions array against [0, arity-1] before constructing ExpressionKeys.
- Derive positions from type.getFieldNames() or type.getArity() rather than hardcoding.
- 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
- Bounds-check position arrays against arity-1 before constructing ExpressionKeys.
- Derive positions from getArity()/getFieldNames() rather than hardcoding.
- Reject negative positions from untrusted input.
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
- Tuple size must be greater than 0. Size: {type.getArity()}
- Tuple position is out of range: {fieldPos}
- Return type {keyType} of KeySelector {keyExtractor.getClass(
- Custom partitioners can only be used with keys that have one
- The partitioner is incompatible with the key type. Partition
AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14).
Data as JSON: /api/errors/d8b839bf9b50f259.
Report an issue: GitHub.