apache/beam · error
main input is global windowed in DoFn
Error message
main input is global windowed in DoFn %v but side input %v is not, cannot map windows correctly. Consider re-windowing the side input PCollection before use
What it means
TryParDo requires that when the main input PCollection is in GlobalWindows, every side input is also in GlobalWindows; otherwise windows of side elements cannot be mapped to the main element's single global window. This validation error fires at graph construction when that combination is detected.
Solutions
- Re-window the side input into GlobalWindows (often with window.WindowInto(window.NewGlobalWindows()) after grouping).
- Alternatively, window the main input to match the side input's windows so per-window lookups make sense.
- If side-input freshness is the goal, use a non-merging windowing on both sides, or use state/timers instead of side inputs.
- Group the side PCollection and view it as a single-element side input in global windows (e.g. via beam.Combine + AsMap patterns adapted to global window).
Example fix
// before
side := s | beam.WindowInto(window.NewFixedWindows(time.Minute))
out := globalMain | beam.ParDo(dofn, beam.SideInput{Input: side}) // error
// after
sideGlobal := side | beam.CombinePerKey(...) | beam.WindowInto(window.NewGlobalWindows())
out := globalMain | beam.ParDo(dofn, beam.SideInput{Input: sideGlobal}) Defensive patterns
Strategy: validation
Validate before calling
// Ensure global-window main inputs only receive global-window side inputs:
if mainWfn.Kind == window.GlobalWindows {
side = side | beam.WindowInto(window.NewGlobalWindows())
} Type guard
func globalWindowed(n *graph.Node) bool {
return n.WindowingStrategy().Fn.Kind == window.GlobalWindows
} Prevention
- When the main input is global-windowed, always re-window side inputs into GlobalWindows after grouping.
- Document windowing requirements on DoFn constructors that accept side inputs.
- Run graph construction (e.g. a small local pipeline test) in CI to catch these errors before deployment.
When it happens
Trigger: beam.ParDo with a GlobalWindows main input and a side input PCollection windowed with FixedWindows/SlidingWindows/Sessions. Fails immediately during pipeline construction.
Common situations: Batch enrichment in streaming pipelines: the main collection defaults to global windows while the lookup table was windowed for freshness; mixing a bounded global-windowed input with a re-windowed static dataset.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- error with side input
- Attempted to get side input window for GlobalWindow from…
- Attempted to get side input window for GlobalWindow from…
- cannot make a keyed iterable for an unkeyed side input
- failed to map main input window to side input window with…
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/4aea8851124f321d.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/go/pkg/beam/pardo.go:66
doFnOpt = graph.NumMainInputs(graph.MainKv)
} else if typex.IsCoGBK(col.Type()) {
doFnOpt = graph.CoGBKMainInput(len(col.Type().Components()))
}
fn, err := graph.NewDoFn(dofn, doFnOpt)
if err != nil {
return nil, addParDoCtx(err, s)
}
in := []*graph.Node{col.n}
inWfn := col.n.WindowingStrategy().Fn
for i, s := range side {
sideNode := s.Input.n
sideWfn := sideNode.WindowingStrategy().Fn
if sideWfn.Kind == window.Sessions {
return nil, fmt.Errorf("error with side input %d in DoFn %v: PCollections using merging WindowFns are not supported as side inputs. Consider re-windowing the side input PCollection before use", i, fn)
}
if (inWfn.Kind == window.GlobalWindows) && (sideWfn.Kind != window.GlobalWindows) {
return nil, fmt.Errorf("main input is global windowed in DoFn %v but side input %v is not, cannot map windows correctly. Consider re-windowing the side input PCollection before use", fn, i)
}
if (sideWfn.Kind == window.GlobalWindows) && !sideNode.Bounded() {
// TODO(https://github.com/apache/beam/issues/21596): Replace this warning with an error return when proper streaming test functions have been added.
log.Warnf(context.Background(), "side input %v is global windowed in DoFn %v but is unbounded, DoFn will block until end of Global Window. Consider windowing your unbounded side input PCollection before use. This will cause your pipeline to fail in a future release, see https://github.com/apache/beam/issues/21596 for details", i, fn)
}
in = append(in, s.Input.n)
}
var rc *coder.Coder
// Sdfs will always encode restrictions as KV<restriction, watermark state | bool(false)>
if fn.IsSplittable() {
sdf := (*graph.SplittableDoFn)(fn)
restT := typex.New(sdf.RestrictionT())
// If no watermark estimator state, use boolean as a placeholder
weT := typex.New(reflect.TypeOf(true))
if sdf.IsStatefulWatermarkEstimating() {
weT = typex.New(sdf.WatermarkEstimatorStateT())
}View on GitHub (pinned to 12126d8942)