apache/flink · error · RuntimeException

Comparator {} specifies an invalid length for the normalized

Error message

Comparator {} specifies an invalid length for the normalized key: {}

What it means

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.

Source

Thrown at flink-core/src/main/java/org/apache/flink/api/java/typeutils/runtime/RowComparator.java:452

            // key
            if (k.supportsNormalizedKey()) {
                if (i == 0) {
                    // the first comparator decides whether we need to invert the key direction
                    inverted = k.invertNormalizedKey();
                } else if (k.invertNormalizedKey() != inverted) {
                    // if a successor does not agree on the inversion direction, it cannot be part
                    // of the
                    // normalized key
                    return new Tuple4<>(
                            normalizedKeyLengths,
                            numLeadingNormalizableKeys,
                            normalizableKeyPrefixLen,
                            inverted);
                }
                numLeadingNormalizableKeys++;
                int len = k.getNormalizeKeyLen();
                if (len < 0) {
                    throw new RuntimeException(
                            "Comparator "
                                    + k.getClass().getName()
                                    + " specifies an invalid length for the normalized key: "
                                    + len);
                }
                normalizedKeyLengths[i] = len;
                normalizableKeyPrefixLen += len;
                if (normalizableKeyPrefixLen < 0) {
                    // overflow, which means we are out of budget for normalized key space anyways
                    return new Tuple4<>(
                            normalizedKeyLengths,
                            numLeadingNormalizableKeys,
                            Integer.MAX_VALUE,
                            inverted);
                }
            } else {
                return new Tuple4<>(
                        normalizedKeyLengths,

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. If you wrote a custom TypeComparator, override getNormalizeKeyLen() to return a non-negative int (>= 0) whenever supportsNormalizedKey() returns true.
  2. 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.
  3. If the faulty comparator comes from a library, file a bug or avoid using that type as a Row key field.
  4. As a workaround, avoid using the problematic field type in the leading key positions of a Row key.

Example fix

// before — custom comparator claims normalized key support but returns -1
public class MyComparator extends TypeComparator<MyType> {
    @Override public boolean supportsNormalizedKey() { return true; }
    // getNormalizeKeyLen() inherited → returns -1 → RowComparator throws
}

// after — override getNormalizeKeyLen to return a valid non-negative length
public class MyComparator extends TypeComparator<MyType> {
    @Override public boolean supportsNormalizedKey() { return true; }
    @Override public int getNormalizeKeyLen() { return 8; } // fixed-length key
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate a custom TypeComparator's normalized-key contract
public static void validateComparatorContract(TypeComparator<?> cmp) {
    if (cmp.supportsNormalizedKey() && cmp.getNormalizeKeyLen() < 0) {
        throw new IllegalStateException(
            cmp.getClass().getName()
            + " supports normalized keys but reports length "
            + cmp.getNormalizeKeyLen() + " (must be >= 0)");
    }
}

Try / catch

// createAuxiliaryFields throws during comparator construction (startup).
// Catch at the point where you build the RowComparator / TypeInformation.
try {
    RowComparator cmp = new RowComparator(arity, keyPositions, comparators, ...);
} catch (RuntimeException e) {
    if (e.getMessage().contains("invalid length for the normalized key")) {
        log.error("A field comparator has a broken normalized-key contract", e);
        // fix the comparator or avoid that field type in the key
    }
    throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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