{"record":{"id":"aba3b372057f9dd1","repo":"apache/flink","slug":"field-fieldnumber-is-accessed-for-a-key-but-out-aba3b3","errorCode":null,"errorMessage":"Field {fieldNumber} is accessed for a key, but out of bounds in the record.","messagePattern":"Field (.+?) is accessed for a key, but out of bounds in the record\\.","errorType":"exception","errorClass":"KeyFieldOutOfBoundsException","httpStatus":null,"severity":"error","filePath":"flink-core/src/main/java/org/apache/flink/api/java/typeutils/runtime/TupleComparatorBase.java","lineNumber":183,"sourceCode":"\n    @Override\n    public int compareToReference(TypeComparator<T> referencedComparator) {\n        TupleComparatorBase<T> other = (TupleComparatorBase<T>) referencedComparator;\n\n        int i = 0;\n        try {\n            for (; i < this.keyPositions.length; i++) {\n                @SuppressWarnings(\"unchecked\")\n                int cmp = this.comparators[i].compareToReference(other.comparators[i]);\n                if (cmp != 0) {\n                    return cmp;\n                }\n            }\n            return 0;\n        } catch (NullPointerException npex) {\n            throw new NullKeyFieldException(keyPositions[i]);\n        } catch (IndexOutOfBoundsException iobex) {\n            throw new KeyFieldOutOfBoundsException(keyPositions[i]);\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public int compareSerialized(DataInputView firstSource, DataInputView secondSource)\n            throws IOException {\n        if (deserializedFields1 == null) {\n            instantiateDeserializationUtils();\n        }\n\n        int i = 0;\n        try {\n            for (; i < serializers.length; i++) {\n                deserializedFields1[i] =\n                        serializers[i].deserialize(deserializedFields1[i], firstSource);\n                deserializedFields2[i] =\n                        serializers[i].deserialize(deserializedFields2[i], secondSource);","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/apache/flink/blob/2f3c205e9266cb30240eb7f4fdab15cad629a70f/flink-core/src/main/java/org/apache/flink/api/java/typeutils/runtime/TupleComparatorBase.java#L165-L201","documentation":"In TupleComparatorBase.compareToReference, an IndexOutOfBoundsException while comparing the reference records is rethrown as KeyFieldOutOfBoundsException(keyPositions[i]). Unlike the TupleComparator paths (which read fields off actual tuples), here the exception typically escapes from a field comparator whose stored reference record is a narrower tuple/object than the configured keyPositions expect.","triggerScenarios":"compareToReference after setReference stored records whose tuple arity is smaller than the comparator's key positions; the field-level comparator then indexes past the record during reference comparison and the IOOBE is wrapped with the tuple-level key position.","commonSituations":"Comparator reused across tuple types of different arity. Mixed-schema streams reaching one keyed operator. Hand-built keyPositions stale after a schema change (same family as 687-690).","solutions":["Re-validate keyPositions against every record type flowing through the operator; enforce a single tuple arity per operator.","Build comparators from the stream's TypeInformation rather than hand-coding positions.","Projection/union steps should guarantee a uniform tuple width before keyed operations."],"exampleFix":"// before\n// comparator built for Tuple3 key {2}; stream carries Tuple2\ncmp.setReference(t2);\ncmp.compareToReference(cmp2); // KeyFieldOutOfBoundsException(2)\n\n// after\n// project all inputs to Tuple3 first, or key on positions valid for Tuple2 (0,1)\nint[] keyPositions = {1};\ncmp.setReference(t2);\ncmp.compareToReference(cmp2);","handlingStrategy":"validation","validationCode":"validateKeyPositions(keyPositions, sampleRecord.getArity()); // all key pos < arity\ncmp.setReference(sampleRecord);","typeGuard":null,"tryCatchPattern":"try {\n    cmp.compareToReference(other);\n} catch (KeyFieldOutOfBoundsException e) {\n    // reference record narrower than key spec: unify tuple arity upstream\n}","preventionTips":["One tuple arity per keyed operator; project heterogeneous inputs to a common type.","Keep keyPositions generated from the active TypeInformation.","Regression-test comparator setup whenever tuple schemas change."],"tags":["tuple","key-position","out-of-bounds","comparator","reference-compare"],"backgroundTag":null,"analyzedSha":"2f3c205e9266cb30240eb7f4fdab15cad629a70f","analyzedAt":"2026-08-14T08:48:24.518Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}