{"record":{"id":"5c9758f17a102198","repo":"apache/beam","slug":"pcollection-does-not-use-a-kvcoder-keyedpcollectiontuple","errorCode":null,"errorMessage":"PCollection does not use a KvCoder","messagePattern":"PCollection does not use a KvCoder","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/join/KeyedPCollectionTuple.java","lineNumber":163,"sourceCode":"\n  /** Returns the {@link CoGbkResultSchema} associated with this {@link KeyedPCollectionTuple}. */\n  public CoGbkResultSchema getCoGbkResultSchema() {\n    return schema;\n  }\n\n  @Override\n  public Pipeline getPipeline() {\n    return pipeline;\n  }\n\n  private static <K, V> Coder<K> getKeyCoder(PCollection<KV<K, V>> pc) {\n    // TODO: This should already have run coder inference for output, but may not have been consumed\n    // as input yet (and won't be fully specified); This is fine\n\n    // Assumes that the PCollection uses a KvCoder.\n    Coder<?> entryCoder = pc.getCoder();\n    if (!(entryCoder instanceof KvCoder<?, ?>)) {\n      throw new IllegalArgumentException(\"PCollection does not use a KvCoder\");\n    }\n    @SuppressWarnings(\"unchecked\")\n    KvCoder<K, V> coder = (KvCoder<K, V>) entryCoder;\n    return coder.getKeyCoder();\n  }\n\n  /////////////////////////////////////////////////////////////////////////////\n\n  /** A utility class to help ensure coherence of tag and input PCollection types. */\n  public static class TaggedKeyedPCollection<K, V> {\n\n    final TupleTag<V> tupleTag;\n    final PCollection<KV<K, V>> pCollection;\n\n    public TaggedKeyedPCollection(TupleTag<V> tupleTag, PCollection<KV<K, V>> pCollection) {\n      this.tupleTag = tupleTag;\n      this.pCollection = pCollection;\n    }","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/join/KeyedPCollectionTuple.java#L145-L181","documentation":"When inferring the key coder from an input PCollection, the tuple requires the PCollection's coder to be a KvCoder so it can extract coder.getKeyCoder(). A non-KvCoder coder means the input isn't a properly-coded KV PCollection.","triggerScenarios":"Adding a PCollection to a KeyedPCollectionTuple whose coder is not a KvCoder, forcing getKeyCoder(pc) inference to fail — same root cause as error 556 but on KeyedPCollectionTuple.and()/getKeyCoder paths.","commonSituations":"Custom sources producing KVs without a KvCoder; PTransforms that set an explicit non-KvCoder coder on a KV PCollection before a join.","solutions":["Set a KvCoder on the PCollection before adding it to the KeyedPCollectionTuple","Use KvCoder.of(keyCoder, valueCoder) and pc.setCoder(...) for inputs from custom IO","Inspect pc.getCoder() type during debugging to confirm it is KvCoder"],"exampleFix":"// before\ntuple.and(tag, pcWithoutKvCoder); // throws\n// after\npc.setCoder(KvCoder.of(StringUtf8Coder.of(), valueCoder));\ntuple.and(tag, pc);","handlingStrategy":"type-guard","validationCode":"if (!(pc.getCoder() instanceof KvCoder)) { throw new IllegalArgumentException(\"KeyedPCollectionTuple input needs a KvCoder\"); }","typeGuard":"if (pc.getCoder() instanceof KvCoder<?, ?> kvCoder) { return kvCoder.getKeyCoder(); }","tryCatchPattern":"try { return getKeyCoder(pc); } catch (IllegalArgumentException e) { pc.setCoder(KvCoder.of(defaultKeyCoder, defaultValueCoder)); return defaultKeyCoder; }","preventionTips":["Set KvCoder on inputs before and()","Use coder inference verified transforms upstream","Unit-test coder types of custom source outputs"],"tags":["beam","kvcoder","coder","keyedpcollectiontuple"],"backgroundTag":"type-mismatch","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}