apache/beam · error · IllegalStateException
cannot return null keyCoder
Error message
cannot return null keyCoder
What it means
getKeyCoder() on a KeyedPCollectionTuple returns the cached keyCoder, but if the tuple was constructed without one (null) and no input has forced inference yet, it refuses to return null and throws an IllegalStateException.
Solutions
- Ensure at least one input PCollection with a KvCoder was added before calling getKeyCoder()
- Construct the KeyedPCollectionTuple with an explicit key coder (e.g. KeyedPCollectionTuple.of creates it from the first input)
- Guard the call with keyCoder null-check via getCoGbkResultSchema/getPipeline introspection instead
Example fix
// before
Coder<K> kCoder = tuple.getKeyCoder(); // NPE-style state error if empty
// after
if (!tuple.isEmpty()) {
Coder<K> kCoder = tuple.getKeyCoder();
} Defensive patterns
Strategy: try-catch
Validate before calling
if (tuple.isEmpty()) { throw new IllegalStateException("Cannot get key coder from empty KeyedPCollectionTuple"); } Try / catch
try { return tuple.getKeyCoder(); } catch (IllegalStateException e) { return inferFromFirstInput(tuple); } Prevention
- Ensure at least one input exists before querying key coder
- Provide key coder explicitly at tuple construction
- Avoid calling getKeyCoder during pipeline construction before inference completes
When it happens
Trigger: Calling getKeyCoder() (or keyCoder-through paths) on a KeyedPCollectionTuple whose keyCoder field is null because no PCollection coder was consulted yet, e.g. on an empty or not-fully-built tuple.
Common situations: Inspecting the key coder before applying the transform; a zero-input tuple passed around for testing; framework code reading keyCoder on a partially constructed tuple.
Related errors
- Attempting to emit an element outside of a @ProcessElement…
- Output coders were already specified
- PCollection does not use a KvCoder
- PCollections come from different Pipelines
- SolaceIO.Write.UnboundedSolaceWriter.Context: No context…
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/3eaea31a4eeea4c1.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/join/KeyedPCollectionTuple.java:141
* Expands the component {@link PCollection PCollections}, stripping off any tag-specific
* information.
*/
@Override
public Map<TupleTag<?>, PValue> expand() {
ImmutableMap.Builder<TupleTag<?>, PValue> retval = ImmutableMap.builder();
for (TaggedKeyedPCollection<K, ?> taggedPCollection : keyedCollections) {
retval.put(taggedPCollection.tupleTag, taggedPCollection.pCollection);
}
return retval.build();
}
/**
* Returns the key {@link Coder} for all {@link PCollection PCollections} in this {@link
* KeyedPCollectionTuple}.
*/
public Coder<K> getKeyCoder() {
if (keyCoder == null) {
throw new IllegalStateException("cannot return null keyCoder");
}
return keyCoder;
}
/** Returns the {@link CoGbkResultSchema} associated with this {@link KeyedPCollectionTuple}. */
public CoGbkResultSchema getCoGbkResultSchema() {
return schema;
}
@Override
public Pipeline getPipeline() {
return pipeline;
}
private static <K, V> Coder<K> getKeyCoder(PCollection<KV<K, V>> pc) {
// TODO: This should already have run coder inference for output, but may not have been consumed
// as input yet (and won't be fully specified); This is fine
View on GitHub (pinned to 12126d8942)