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
- 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.
- If plain iteration is intended, access the side input through the non-keyed path (NewIterable) instead.
- Check the side input's access/type info in the pipeline proto (side input ID %v) matches the consumer's expectation.
- 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
- Match view type (iterable vs multimap) to how the side input is declared
- Key the producing PCollection if keyed access is required
- Check side input IDs in the pipeline proto match consumers
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
- cannot make a state provider for an unkeyed input
- error with side input
- main input is global windowed in DoFn
- mismatched Flatten input types
- missing side input info for collection
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)