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
- Filter or reject null entries from the key-expression array before use.
- Use a List<String> and removeIf(Objects::isNull), or validate at the source.
- 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
- Filter nulls from programmatic field lists before passing them as keys.
- Use List.removeIf(Objects::isNull) or validate at the source.
- Fail fast at the config layer when a required field name is missing.
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
- Tuple size must be greater than 0. Size: {type.getArity()}
- The grouping fields must not be empty.
- This type ({ffd.getType()}) cannot be used as key.
- Unable to extract key from expression '{keyExpr}' on key {cT
- Key extractor must not be null.
AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14).
Data as JSON: /api/errors/b2274c27cd3791ca.
Report an issue: GitHub.