apache/beam · error

multimap side inputs needs KV coder, got

Error message

multimap side inputs needs KV coder, got %v

What it means

Multimap side inputs require the input PCollection to be a KV pair so keys can be mapped to lists of values. If the coder's URN is not beam:coder:kv, handleSideInput rejects the access pattern with this error, naming the actual URN found.

Solutions

  1. Ensure the side input PCollection is a KV collection (beam.KV) before using a multimap view
  2. Use beam.AsMap (single-map) instead of multimap view if elements are not KV
  3. Check that upstream ParDo outputs KV-coded PCollections
  4. Inspect the reported URN in the message to confirm the coder type mismatch

Example fix

// before
si := beam.SideInput(pcoll) // pcoll is of type T, not KV
// after
kvPcol := beam.ParDo(p, func(t T) (K, V) {...}, input)
si := beam.SideInput(kvPcol) // KV coder required for multimap
Defensive patterns

Strategy: type-guard

Validate before calling

// Before using a multimap side input, assert KV typing
coderURN := coderURNOf(sideInputPcol)
if coderURN != "beam:coder:kv:v1" {
    return fmt.Errorf("multimap side input requires KV, got %s", coderURN)
}

Type guard

func isKVCoder(c *pipepb.Coder) bool {
    return c.GetSpec().GetUrn() == "beam:coder:kv:v1"
}

Prevention

When it happens

Trigger: A pipeline uses a multimap side input access pattern while the side input PCollection's coder is not a KV coder (e.g. a plain element coder, or an iterable/window coder instead of KV).

Common situations: Using beam.AsMap or multimap views over non-K<->V collections; forgetting beam.KV for side input elements; SDK constructs emitting windowed values instead of KV.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at sdks/go/pkg/beam/runners/prism/internal/stage.go:734

			if b.IterableSideInputData == nil {
				b.IterableSideInputData = map[worker.SideInputKey]map[typex.Window][][]byte{}
			}
			b.IterableSideInputData[worker.SideInputKey{
				TransformID: link.Transform,
				Local:       link.Local,
			}] = data
		}, nil

	case urns.SideInputMultiMap:
		slog.Debug("urnSideInputMultiMap",
			slog.String("sourceTransform", t.GetUniqueName()),
			slog.String("local", link.Local),
			slog.String("global", link.Global))
		col := pcols[link.Global]

		kvc := comps.GetCoders()[col.GetCoderId()]
		if kvc.GetSpec().GetUrn() != urns.CoderKV {
			return nil, fmt.Errorf("multimap side inputs needs KV coder, got %v", kvc.GetSpec().GetUrn())
		}

		kd := collectionPullDecoder(kvc.GetComponentCoderIds()[0], coders, comps)
		vd := collectionPullDecoder(kvc.GetComponentCoderIds()[1], coders, comps)

		// The returned coders are unused here, but they add the side input coders
		// to the stage components for use SDK side.
		getWindowValueCoders(comps, col, coders)
		return func(b *worker.B, watermark mtime.Time) {
			// May be of zero length, but that's OK. Side inputs can be empty.
			data := em.GetSideData(b.PBDID, link.Transform, link.Local, watermark)
			if b.MultiMapSideInputData == nil {
				b.MultiMapSideInputData = map[worker.SideInputKey]map[typex.Window]map[string][][]byte{}
			}

			windowed := map[typex.Window]map[string][][]byte{}
			for win, ds := range data {
				if len(ds) == 0 {

View on GitHub (pinned to 12126d8942)