{"record":{"id":"be7c905e4c170dab","repo":"apache/flink","slug":"comparator-specifies-an-invalid-length-for-the-be7c90","errorCode":null,"errorMessage":"Comparator {} specifies an invalid length for the normalized key: {}","messagePattern":"Comparator (.+?) specifies an invalid length for the normalized key: (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"flink-core/src/main/java/org/apache/flink/api/java/typeutils/runtime/RowComparator.java","lineNumber":452,"sourceCode":"            // key\n            if (k.supportsNormalizedKey()) {\n                if (i == 0) {\n                    // the first comparator decides whether we need to invert the key direction\n                    inverted = k.invertNormalizedKey();\n                } else if (k.invertNormalizedKey() != inverted) {\n                    // if a successor does not agree on the inversion direction, it cannot be part\n                    // of the\n                    // normalized key\n                    return new Tuple4<>(\n                            normalizedKeyLengths,\n                            numLeadingNormalizableKeys,\n                            normalizableKeyPrefixLen,\n                            inverted);\n                }\n                numLeadingNormalizableKeys++;\n                int len = k.getNormalizeKeyLen();\n                if (len < 0) {\n                    throw new RuntimeException(\n                            \"Comparator \"\n                                    + k.getClass().getName()\n                                    + \" specifies an invalid length for the normalized key: \"\n                                    + len);\n                }\n                normalizedKeyLengths[i] = len;\n                normalizableKeyPrefixLen += len;\n                if (normalizableKeyPrefixLen < 0) {\n                    // overflow, which means we are out of budget for normalized key space anyways\n                    return new Tuple4<>(\n                            normalizedKeyLengths,\n                            numLeadingNormalizableKeys,\n                            Integer.MAX_VALUE,\n                            inverted);\n                }\n            } else {\n                return new Tuple4<>(\n                        normalizedKeyLengths,","sourceCodeStart":434,"sourceCodeEnd":470,"githubUrl":"https://github.com/apache/flink/blob/2f3c205e9266cb30240eb7f4fdab15cad629a70f/flink-core/src/main/java/org/apache/flink/api/java/typeutils/runtime/RowComparator.java#L434-L470","documentation":"RowComparator.createAuxiliaryFields() validates that every sub-comparator that claims to support normalized keys reports a non-negative key length via getNormalizeKeyLen(). If a sub-comparator returns a negative length (a contract violation), this RuntimeException is thrown during comparator construction. The message names the offending comparator class and the invalid length value.","triggerScenarios":"During RowComparator construction (which happens when Flink builds the TypeComparator for a Row used as a key in a DataSet sort/group/join), createAuxiliaryFields iterates the per-field NullAwareComparators. If one reports supportsNormalizedKey()==true but getNormalizeKeyLen() < 0, the exception fires. This indicates a bug in a custom TypeComparator implementation or an inconsistent comparator built via the type system.","commonSituations":"A custom TypeComparator implementation overrides supportsNormalizedKey() to return true but forgets to override getNormalizeKeyLen() (inheriting a default that returns -1); a composite/comparator wrapper miscomputes the normalized key length; a third-party connector or library provides a faulty TypeComparator for a field type used in a Row key.","solutions":["If you wrote a custom TypeComparator, override getNormalizeKeyLen() to return a non-negative int (>= 0) whenever supportsNormalizedKey() returns true.","Audit the field types in the Row key: identify which one's comparator reports a negative normalized key length (the message includes the class name) and fix or replace that comparator.","If the faulty comparator comes from a library, file a bug or avoid using that type as a Row key field.","As a workaround, avoid using the problematic field type in the leading key positions of a Row key."],"exampleFix":"// before — custom comparator claims normalized key support but returns -1\npublic class MyComparator extends TypeComparator<MyType> {\n    @Override public boolean supportsNormalizedKey() { return true; }\n    // getNormalizeKeyLen() inherited → returns -1 → RowComparator throws\n}\n\n// after — override getNormalizeKeyLen to return a valid non-negative length\npublic class MyComparator extends TypeComparator<MyType> {\n    @Override public boolean supportsNormalizedKey() { return true; }\n    @Override public int getNormalizeKeyLen() { return 8; } // fixed-length key\n}","handlingStrategy":"validation","validationCode":"// Validate a custom TypeComparator's normalized-key contract\npublic static void validateComparatorContract(TypeComparator<?> cmp) {\n    if (cmp.supportsNormalizedKey() && cmp.getNormalizeKeyLen() < 0) {\n        throw new IllegalStateException(\n            cmp.getClass().getName()\n            + \" supports normalized keys but reports length \"\n            + cmp.getNormalizeKeyLen() + \" (must be >= 0)\");\n    }\n}","typeGuard":null,"tryCatchPattern":"// createAuxiliaryFields throws during comparator construction (startup).\n// Catch at the point where you build the RowComparator / TypeInformation.\ntry {\n    RowComparator cmp = new RowComparator(arity, keyPositions, comparators, ...);\n} catch (RuntimeException e) {\n    if (e.getMessage().contains(\"invalid length for the normalized key\")) {\n        log.error(\"A field comparator has a broken normalized-key contract\", e);\n        // fix the comparator or avoid that field type in the key\n    }\n    throw e;\n}","preventionTips":["When implementing a custom TypeComparator, always override getNormalizeKeyLen() if supportsNormalizedKey() returns true.","Unit-test custom comparators for the normalized-key contract before using them in Row keys.","Avoid using exotic or third-party field types in Row key positions.","Validate the comparator contract in CI for all serialized types."],"tags":["row","comparator","normalized-key","comparator-contract","custom-comparator"],"backgroundTag":null,"analyzedSha":"2f3c205e9266cb30240eb7f4fdab15cad629a70f","analyzedAt":"2026-08-14T08:48:24.518Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}