apache/beam · error

main and finally trigger arguments to trigger.OrFinally()…

Error message

main and finally trigger arguments to trigger.OrFinally() cannot be nil

What it means

OrFinally combines a main trigger (which may fire repeatedly) with a finally trigger that ends output. Both arguments must be non-nil; passing either as nil is a programming error, so the constructor panics rather than returning a broken trigger.

Solutions

  1. Check both triggers for nil before calling OrFinally and substitute valid triggers.
  2. Trace why the trigger variable is nil — usually an unassigned branch or a factory returning nil on error.
  3. Return a default trigger when configuration yields none.

Example fix

// before
t := trigger.OrFinally(main, fin) // panics if either is nil
// after
if main == nil {
	main = trigger.DefaultTrigger()
}
if fin == nil {
	fin = trigger.AfterEndOfWindow()
}
t := trigger.OrFinally(main, fin)
Defensive patterns

Strategy: validation

Validate before calling

if main == nil || fin == nil {
	return fmt.Errorf("OrFinally requires non-nil main and finally triggers")
}
t := trigger.OrFinally(main, fin)

Type guard

func validOrFinallyArgs(main, fin trigger.Trigger) bool { return main != nil && fin != nil }

Prevention

When it happens

Trigger: Calling trigger.OrFinally(nil, finally), OrFinally(main, nil), or OrFinally(nil, nil), typically because a variable holding a trigger was never initialized or a factory function returned nil.

Common situations: Conditionally building triggers where an if-branch forgets to assign the trigger, or a lookup/config parse returns nil and the nil is passed straight through.

Related errors


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

Appendix: source

Thrown at sdks/go/pkg/beam/core/graph/window/trigger/trigger.go:329

// OrFinallyTrigger is ready whenever either of its subtriggers are ready, but finishes output
// when the finally subtrigger fires.
type OrFinallyTrigger struct {
	main    Trigger // Trigger governing main output; may fire repeatedly.
	finally Trigger // Trigger governing termination of output.
}

// String implements the Stringer interface and returns trigger details as a string.
func (t *OrFinallyTrigger) String() string {
	return fmt.Sprintf("%#v", t)
}

func (t OrFinallyTrigger) trigger() {}

// OrFinally trigger has main trigger which may fire repeatedly and the finally trigger.
// Output is produced when the finally trigger fires.
func OrFinally(main, finally Trigger) *OrFinallyTrigger {
	if main == nil || finally == nil {
		panic("main and finally trigger arguments to trigger.OrFinally() cannot be nil")
	}
	return &OrFinallyTrigger{main: main, finally: finally}
}

// Main returns the main trigger of OrFinallyTrigger.
func (t *OrFinallyTrigger) Main() Trigger {
	return t.main
}

// Finally returns the finally trigger of OrFinallyTrigger.
func (t *OrFinallyTrigger) Finally() Trigger {
	return t.finally
}

// NeverTrigger is never ready to fire.
type NeverTrigger struct{}

// String implements the Stringer interface and returns trigger details as a string.

View on GitHub (pinned to 12126d8942)