apache/flink · error · IllegalStateException

Missing key '{}'

Error message

Missing key '{}'

What it means

LinkedOptionalMap stores named key/value pairs where either side may be absent (wrapped Optional-like semantics via null KeyValue fields). unwrapOptionals() strips the Optional layer into a plain LinkedHashMap, and throws IllegalStateException if an entry's key is null — i.e. the entry was added as an optional/marker entry whose key was never supplied.

Source

Thrown at flink-core/src/main/java/org/apache/flink/util/LinkedOptionalMap.java:185

                .map(Entry::getValue)
                .collect(Collectors.toCollection(LinkedHashSet::new));
    }

    /**
     * Assuming all the entries of this map are present (keys and values) this method would return a
     * map with these key and values, stripped from their Optional wrappers. NOTE: please note that
     * if any of the key or values are absent this method would throw an {@link
     * IllegalStateException}.
     */
    public LinkedHashMap<K, V> unwrapOptionals() {
        final LinkedHashMap<K, V> unwrapped =
                CollectionUtil.newLinkedHashMapWithExpectedSize(underlyingMap.size());

        for (Entry<String, KeyValue<K, V>> entry : underlyingMap.entrySet()) {
            String namedKey = entry.getKey();
            KeyValue<K, V> kv = entry.getValue();
            if (kv.key == null) {
                throw new IllegalStateException("Missing key '" + namedKey + "'");
            }
            if (kv.value == null) {
                throw new IllegalStateException("Missing value for the key '" + namedKey + "'");
            }
            unwrapped.put(kv.key, kv.value);
        }
        return unwrapped;
    }

    /** Returns the key names added to this map. */
    public Set<String> keyNames() {
        return underlyingMap.keySet();
    }

    // --------------------------------------------------------------------------------------------------------
    // Static Utility Methods
    // --------------------------------------------------------------------------------------------------------

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Find which entry name (printed in the message) has a missing key and ensure both key and value are set when adding it.
  2. Before unwrapping, call keyNames() / inspect entries and drop or complete entries with absent keys instead of unwrapping blindly.
  3. If the entry is genuinely optional, skip adding it at all rather than adding it half-populated.
  4. Add a unit test that asserts every registered entry is complete before unwrapOptionals is reached.

Example fix

// before
map.putOptional("module-a", /* key absent */ null, moduleValue);
map.unwrapOptionals(); // IllegalStateException: Missing key 'module-a'

// after
if (moduleKey != null) {
    map.put("module-a", moduleKey, moduleValue);
}
map.unwrapOptionals();
Defensive patterns

Strategy: validation

Validate before calling

for (String name : map.keyNames()) {
    if (!map.containsKey(name)) { // or equivalent accessor showing key is absent
        throw new IllegalStateException("Entry '" + name + "' has no key; complete or remove it");
    }
}
LinkedHashMap<K, V> m = map.unwrapOptionals();

Prevention

When it happens

Trigger: Calling unwrapOptionals() after adding entries with a null key — via put/putOptional-style methods where only a value or only a name was recorded (KeyValue.key == null) — such as in Table/SQL module or catalog wiring that uses LinkedOptionalMap for optional dependencies.

Common situations: Building a pipeline of optional components (e.g. table module loading, function catalog setup) where a component was registered by name but its key object was left absent, then a downstream consumer demands fully-populated entries by calling unwrapOptionals().

Related errors


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