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

  1. Re-window the side input into GlobalWindows (often with window.WindowInto(window.NewGlobalWindows()) after grouping).
  2. Alternatively, window the main input to match the side input's windows so per-window lookups make sense.
  3. If side-input freshness is the goal, use a non-merging windowing on both sides, or use state/timers instead of side inputs.
  4. 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 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


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)