apache/beam · error

cannot make a keyed iterable for an unkeyed side input

Error message

cannot make a keyed iterable for an unkeyed side input %v

What it means

sideInputAdapter.NewKeyedIterable builds a ReStream for a multimap (keyed) side input. It requires a key coder (kc); if the side input was registered as unkeyed (single-iteration side input), keyed access is impossible and this error names the offending side input ID. It flags a mismatch between how the side input was declared and how it is consumed.

Solutions

  1. Declare the side input as a keyed/multimap view (e.g. use beam.Combine_perKey or CoGBK-style keyed access) if keyed lookup is intended.
  2. If plain iteration is intended, access the side input through the non-keyed path (NewIterable) instead.
  3. Check the side input's access/type info in the pipeline proto (side input ID %v) matches the consumer's expectation.
  4. Ensure both producing and consuming transforms were built with consistent Beam version/view types.

Example fix

// before: keyed access to a plain iterable side input
side := beam.SideInput{Input: unkeyedPCol}
// after: materialize as a keyed view first
keyed := beam.ParDo(s, func(k string, v string, _ func(*string, func(string) bool)) (string, string) { return k, v }, pcol)
side := beam.SideInput{Input: keyed} // now keyed/multimap access is valid
Defensive patterns

Strategy: validation

Validate before calling

if adapter.Kc() == nil { return errors.New("side input is unkeyed; use NewIterable not NewKeyedIterable") }

Type guard

func isKeyedSideInput(s *exec.SideInputAdapter) bool { return s != nil && s.HasKeyCoder() }

Try / catch

stream, err := adapter.NewKeyedIterable(ctx, reader, w, key)
if err != nil && strings.Contains(err.Error(), "unkeyed side input") {
    stream, err = adapter.NewIterable(ctx, reader, w)
}

Prevention

When it happens

Trigger: Calling NewKeyedIterable for a side input whose adapter was created without a key coder — i.e. accessing an Iterable side input as if it were a Map/Multimap side input.

Common situations: Pipeline declares a plain side input (beam.SideInput of an unordered/iterable PCollection) but the transform accesses it keyed (e.g. via a multimap view); translation emits wrong access info; custom runners calling the adapter directly with wrong iterKey.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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

Appendix: source

Thrown at sdks/go/pkg/beam/core/runtime/exec/sideinput.go:109

	// Cache miss, build new ReStream
	r := &proxyReStream{
		open: func() (Stream, error) {
			r, err := reader.OpenIterableSideInput(ctx, s.sid, s.sideInputID, win)
			if err != nil {
				return nil, err
			}
			return &elementStream{r: r, ec: s.ec}, nil
		},
	}
	return cache.SetCache(ctx, s.sid.PtransformID, s.sideInputID, win, key, r), nil
}

// NewKeyedIterable returns a ReStream of a multimap side input from the runner, either by getting the ReStream from
// the side input cache or by opening a new stream and reading it in.
func (s *sideInputAdapter) NewKeyedIterable(ctx context.Context, reader StateReader, w typex.Window, iterKey any) (ReStream, error) {
	if s.kc == nil {
		return nil, fmt.Errorf("cannot make a keyed iterable for an unkeyed side input %v", s.sideInputID)
	}
	key, err := EncodeElement(s.kc, iterKey)
	if err != nil {
		return nil, err
	}
	mw, err := s.wm.MapWindow(w)
	if err != nil {
		return nil, err
	}
	win, err := EncodeWindow(s.wc, mw)
	if err != nil {
		return nil, err
	}
	cache := reader.GetSideInputCache()
	// Cache hit
	if r := cache.QueryCache(ctx, s.sid.PtransformID, s.sideInputID, win, key); r != nil {
		return r, nil
	}

View on GitHub (pinned to 12126d8942)