apache/flink · error · InvalidProgramException

This type ({type}) cannot be used as key.

Error message

This type ({type}) cannot be used as key.

What it means

Thrown by Keys.ExpressionKeys(String[], TypeInformation) in the else-branch where the data type is NOT a CompositeType. For atomic/non-composite types the entire type must itself satisfy isKeyType(). If the type is both non-composite and non-key-type (e.g. a raw Object, a byte array, or a GenericTypeInfo wrapping an unrecognised class), no key can be extracted at all.

Source

Thrown at flink-core/src/main/java/org/apache/flink/api/common/operators/Keys.java:343

                    for (FlatFieldDescriptor field : flatFields) {
                        if (!field.getType().isKeyType()) {
                            throw new InvalidProgramException(
                                    "This type (" + field.getType() + ") cannot be used as key.");
                        }
                    }
                    // add flat fields to key fields
                    keyFields.addAll(flatFields);

                    String strippedKeyExpr = WILD_CARD_REGEX.matcher(keyExpr).replaceAll("");
                    if (strippedKeyExpr.isEmpty()) {
                        this.originalKeyTypes[i] = type;
                    } else {
                        this.originalKeyTypes[i] = cType.getTypeAt(strippedKeyExpr);
                    }
                }
            } else {
                if (!type.isKeyType()) {
                    throw new InvalidProgramException(
                            "This type (" + type + ") cannot be used as key.");
                }

                // check that all key expressions are valid
                for (String keyExpr : keyExpressions) {
                    if (keyExpr == null) {
                        throw new InvalidProgramException("Expression key may not be null.");
                    }
                    // strip off whitespace
                    keyExpr = keyExpr.trim();
                    // check that full type is addressed
                    if (!(SELECT_ALL_CHAR.equals(keyExpr)
                            || SELECT_ALL_CHAR_SCALA.equals(keyExpr))) {
                        throw new InvalidProgramException(
                                "Field expression must be equal to '"
                                        + SELECT_ALL_CHAR
                                        + "' or '"
                                        + SELECT_ALL_CHAR_SCALA

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Wrap the value in a Tuple1 or a properly-annotated POJO and keyBy on the inner field.
  2. Supply a KeySelector<T, K> to keyBy that extracts a primitive/String key from the object.
  3. Register a TypeInfoFactory for the class so Flink recognises it as a composite or key type.
  4. Avoid using byte[], Object[], or raw generics as keys; convert to a comparable wrapper first.

Example fix

// before
DataStream<MyObject> ds = ...;
ds.keyBy("*");  // MyObject is GenericTypeInfo → not key type

// after
ds.keyBy(obj -> obj.getId());  // KeySelector extracting a String
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(type instanceof CompositeType) && !type.isKeyType()) {
    throw new IllegalArgumentException(
        "Type " + type + " is neither composite nor a valid key type.");
}

Type guard

static boolean canBeUsedAsKey(TypeInformation<?> type) {
    return (type instanceof CompositeType) || type.isKeyType();
}

Try / catch

try {
    new Keys.ExpressionKeys<>(exprs, type);
} catch (InvalidProgramException e) {
    if (e.getMessage().contains("cannot be used as key")) {
        ds.keyBy(new KeySelector<T,String>(){ ... });
    } else throw e;
}

Prevention

When it happens

Trigger: Passing a non-composite, non-key type such as ObjectType, a raw array, or a GenericTypeInfo to ExpressionKeys with a field expression. Calling keyBy on a DataStream<SomeRandomClass> where SomeRandomClass is neither a recognised POJO/Tuple nor itself a valid key type.

Common situations: Using DataStream<MyDomainObject> without registering type info, so Flink treats it as GenericTypeInfo. Attempting to use an opaque/third-party Java object directly as a key without a KeySelector.

Related errors


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