apache/beam · critical

KV coder with more than 2 components

Error message

KV coder with more than 2 components: %s

What it means

The prism runner builds pull-based decoders for pipeline coders. A KV coder must have exactly two component coders (key and value); this panic fires when the pipeline harness hands prism a KV coder whose component list has any other length, meaning the coder graph sent by the SDK is malformed.

Solutions

  1. Inspect the coder proto in the panic message (prototext format) and check the component_coder_ids count
  2. Verify SDK and prism runner versions match (use the same Beam release on both sides)
  3. Reproduce with a minimal pipeline to identify the transform producing the bad coder
  4. File/inspect a Beam issue if the SDK legitimately emitted a malformed KV coder

Example fix

// before: constructing a KV coder manually with wrong components
coder := pipepb.Coder{Spec: ...} // components omitted
// after: ensure exactly 2 component coder IDs are set
if len(kvCoder.GetComponentCoderIds()) != 2 { /* fix coder construction */ }
Defensive patterns

Strategy: validation

Validate before calling

if len(kvCoder.GetComponentCoderIds()) != 2 { return fmt.Errorf("KV coder must have exactly 2 components, got %d", len(kvCoder.GetComponentCoderIds())) }

Try / catch

// panics are not recoverable at this layer; recover only at the harness boundary
defer func() { if r := recover(); r != nil { log.Errorf("coder setup panicked: %v", r) } }()

Prevention

When it happens

Trigger: pullDecoderNoAlloc encounters a proto coder with urn beam:coders:kv:v1 whose GetComponentCoderIds() returns != 2, e.g. a KV coder referencing zero, one, or three+ component coder IDs, typically due to a corrupted or hand-edited pipeline proto or an SDK-side coder-construction bug.

Common situations: Running pipelines cross-language where one SDK emits a malformed KV coder; SDK/runner version skew where coder representation changed; custom DoFns or coders that assemble KV coders programmatically with the wrong number of components.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/cf38be4c7797bc92. Report an issue: GitHub.

Appendix: source

Thrown at sdks/go/pkg/beam/runners/prism/internal/coders.go:351

		return func(r io.Reader) {
			coder.DecodeDouble(r)
		}
	case urns.CoderIterable:
		ccids := c.GetComponentCoderIds()
		if len(ccids) != 1 {
			panic(fmt.Sprintf("Iterable coder must have only one component: %s", prototext.Format(c)))
		}
		ed := pullDecoderNoAlloc(coders[ccids[0]], coders)
		return func(r io.Reader) {
			l, _ := coder.DecodeInt32(r)
			for i := int32(0); i < l; i++ {
				ed(r)
			}
		}
	case urns.CoderKV:
		ccids := c.GetComponentCoderIds()
		if len(ccids) != 2 {
			panic(fmt.Sprintf("KV coder with more than 2 components: %s", prototext.Format(c)))
		}
		kd := pullDecoderNoAlloc(coders[ccids[0]], coders)
		vd := pullDecoderNoAlloc(coders[ccids[1]], coders)
		return func(r io.Reader) {
			kd(r)
			vd(r)
		}
	case urns.CoderWindowedValue:
		ccids := c.GetComponentCoderIds()
		if len(ccids) != 2 {
			panic(fmt.Sprintf("WindowedValue coder with more than 2 components: %s", prototext.Format(c)))
		}
		ed := pullDecoderNoAlloc(coders[ccids[0]], coders)
		wd := pullDecoderNoAlloc(coders[ccids[1]], coders)
		return func(r io.Reader) {
			ed(r)
			wd(r)
		}

View on GitHub (pinned to 12126d8942)