apache/flink · error · InvalidProgramException

Expression key may not be null.

Error message

Expression key may not be null.

What it means

Thrown by ExpressionKeys(String[], TypeInformation) when one of the key expression strings is null. Field-expression keys like groupBy("userId") must each be a non-null string; a null entry (often from a list with a gap) cannot be resolved against the type.

Source

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

            this(new String[] {keyExpression}, type);
        }

        /** Create String-based (nested) field expression keys on a composite type. */
        public ExpressionKeys(String[] keyExpressions, TypeInformation<T> type) {
            checkNotNull(keyExpressions, "Field expression cannot be null.");

            this.keyFields = new ArrayList<>(keyExpressions.length);

            if (type instanceof CompositeType) {
                CompositeType<T> cType = (CompositeType<T>) type;
                this.originalKeyTypes = new TypeInformation<?>[keyExpressions.length];

                // extract the keys on their flat position
                for (int i = 0; i < keyExpressions.length; i++) {
                    String keyExpr = keyExpressions[i];

                    if (keyExpr == null) {
                        throw new InvalidProgramException("Expression key may not be null.");
                    }
                    // strip off whitespace
                    keyExpr = keyExpr.trim();

                    List<FlatFieldDescriptor> flatFields = cType.getFlatFields(keyExpr);

                    if (flatFields.size() == 0) {
                        throw new InvalidProgramException(
                                "Unable to extract key from expression '"
                                        + keyExpr
                                        + "' on key "
                                        + cType);
                    }
                    // check if all nested fields can be used as keys
                    for (FlatFieldDescriptor field : flatFields) {
                        if (!field.getType().isKeyType()) {
                            throw new InvalidProgramException(
                                    "This type (" + field.getType() + ") cannot be used as key.");

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Filter or reject null entries from the key-expression array before use.
  2. Use a List<String> and removeIf(Objects::isNull), or validate at the source.
  3. Fail fast with a clear error naming which configured field is missing.

Example fix

// before
String[] keys = {"a", config.get("b"), "c"}; // config.get("b") may be null
ds.groupBy(keys);
// after
List<String> keys = new ArrayList<>(Arrays.asList("a", config.get("b"), "c"));
keys.removeIf(Objects::isNull);
ds.groupBy(keys.toArray(new String[0]));
Defensive patterns

Strategy: validation

Validate before calling

for (String e : keyExpressions) {
    if (e == null) throw new IllegalArgumentException("Key expression must not be null");
}

Prevention

When it happens

Trigger: Passing a String[] with a null element to ExpressionKeys or groupBy(String...); building key expressions from a Map whose get() returned null for some field; array initialisation that left a slot null.

Common situations: Programmatic field lists with optional entries that defaulted to null; config-driven field names where one key was missing; refactors that introduced a null into a previously all-literal list.

Related errors


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