apache/flink · error · KeyFieldOutOfBoundsException
{}
Error message
{} What it means
RowComparator.hash() iterates the configured key positions and calls record.getField(keyPositions[i]) on each. If a key position index is beyond the Row's arity (number of fields), Row.getField raises IndexOutOfBoundsException, which is caught and re-thrown as KeyFieldOutOfBoundsException with the message 'Field N is accessed for a key, but out of bounds in the record.' The comparator and the Row disagree on how many fields the Row has.
Source
Thrown at flink-core/src/main/java/org/apache/flink/api/java/typeutils/runtime/RowComparator.java:181
public void getFlatComparator(List<TypeComparator> flatComparators) {
for (NullAwareComparator<Object> c : comparators) {
Collections.addAll(flatComparators, c.getFlatComparators());
}
}
@Override
public int hash(Row record) {
int code = 0;
int i = 0;
try {
for (; i < keyPositions.length; i++) {
code *= TupleComparatorBase.HASH_SALT[i & 0x1F];
Object element = record.getField(keyPositions[i]); // element can be null
code += comparators[i].hash(element);
}
} catch (IndexOutOfBoundsException e) {
throw new KeyFieldOutOfBoundsException(keyPositions[i]);
}
return code;
}
@Override
public void setReference(Row toCompare) {
int i = 0;
try {
for (; i < keyPositions.length; i++) {
TypeComparator<Object> comparator = comparators[i];
Object element = toCompare.getField(keyPositions[i]);
comparator.setReference(element); // element can be null
}
} catch (IndexOutOfBoundsException e) {
throw new KeyFieldOutOfBoundsException(keyPositions[i]);
}
}View on GitHub (pinned to 2f3c205e92)
Solutions
- Align the key position indices with the actual Row arity — verify Row.getArity() matches the comparator's expected arity before the operation.
- If you changed the Row schema, update the key specification (keyBy / sort / groupBy field indices) to reference valid positions.
- Trace the upstream operator that produces the Row and confirm its output arity; add an arity check in a MapFunction if needed.
- If restoring from a savepoint with a schema mismatch, implement a state migration or start from a clean savepoint.
Example fix
// before — comparator keys on position 2 but Rows only have 2 fields (indices 0,1) dataSet.sortPartition(2, Order.ASCENDING); // Row arity = 2 → IOOBE // after — key on a valid position within the Row's arity dataSet.sortPartition(1, Order.ASCENDING); // valid: index 1 < arity 2
Defensive patterns
Strategy: validation
Validate before calling
// Before hashing or keying a Row, validate all key positions are in bounds
public static void validateKeyPositions(Row row, int[] keyPositions) {
for (int pos : keyPositions) {
if (pos < 0 || pos >= row.getArity()) {
throw new IllegalArgumentException(
"Key position " + pos + " is out of bounds for Row arity " + row.getArity());
}
}
} Try / catch
try {
int hash = comparator.hash(record);
} catch (KeyFieldOutOfBoundsException e) {
log.error("Row arity {} too small for key position {}",
record.getArity(), e.getFieldNumber());
throw e;
} Prevention
- Validate Row.getArity() >= (max(keyPositions)+1) before any keyed operation.
- Keep key position arrays in sync with the Row schema — update both together.
- Add a schema-validation MapFunction at the pipeline entry point.
- Document expected Row arity alongside key specifications.
When it happens
Trigger: The RowComparator is configured with keyPositions referencing field indices that the actual Row at runtime does not contain — e.g., comparator keys on position 3 but the Row only has 2 fields. This arises when the comparator's arity assumption diverges from the data's actual arity.
Common situations: The Row schema was changed (fields added or removed) without updating the key specification; a keyBy / sort uses positional indices computed against one schema but the upstream operator emits Rows with a different arity; a DataSet groupBy/sort with key positions [0,1,2] receives Rows of arity 2 due to a projection that was added without updating keys; legacy savepoint data with an older Row arity restored into a job whose comparator expects more fields.
Related errors
- Record serialization with leading normalized keys not suppor
- Record deserialization with leading normalized keys not supp
- Input type of coGroup must be one of composite types or atom
- Input types of coGroup must be composite types.
- Input type of GroupCombine must be one of composite types or
AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14).
Data as JSON: /api/errors/ee21a1daca2b261a.
Report an issue: GitHub.