apache/beam · error

number of subtriggers to trigger.AfterAll() should be…

Error message

number of subtriggers to trigger.AfterAll() should be greater than 1, got: %v

What it means

trigger.AfterAll() builds an AfterAllTrigger that fires only after every subtrigger has fired. The library panics when the slice has fewer than two subtriggers, since an 'all' semantics over 0 or 1 triggers is degenerate. This is a fail-fast argument validation panic.

Solutions

  1. Pass at least two triggers to AfterAll.
  2. Guard the call: if len(triggers) == 1 use triggers[0] directly.
  3. If zero triggers, choose an appropriate default trigger instead of AfterAll.

Example fix

// before
t := trigger.AfterAll(subs) // panics if len(subs) <= 1
// after
if len(subs) == 1 {
	t = subs[0]
} else {
	t = trigger.AfterAll(subs)
}
Defensive patterns

Strategy: validation

Validate before calling

if len(subs) < 2 {
	return fmt.Errorf("AfterAll needs >= 2 subtriggers, got %d", len(subs))
}
t := trigger.AfterAll(subs)

Type guard

func canAfterAll(ts []trigger.Trigger) bool { return len(ts) > 1 }

Prevention

When it happens

Trigger: Calling trigger.AfterAll(nil), AfterAll([]Trigger{}), or AfterAll with a single-element slice; note the panic message reports len(triggers).

Common situations: Assembling subtriggers from user configuration or a pipeline spec where the list is empty or has one entry; refactoring code that previously passed several triggers down to one.

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/cca1b30d1f0fbe70. Report an issue: GitHub.

Appendix: source

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

	subtriggers []Trigger
}

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

func (t AfterAllTrigger) trigger() {}

// SubTriggers returns the component triggers.
func (t *AfterAllTrigger) SubTriggers() []Trigger {
	return t.subtriggers
}

// AfterAll returns a new AfterAll trigger with subtriggers set to the passed argument.
func AfterAll(triggers []Trigger) *AfterAllTrigger {
	if len(triggers) <= 1 {
		panic(fmt.Sprintf("number of subtriggers to trigger.AfterAll() should be greater than 1, got: %v", len(triggers)))
	}
	return &AfterAllTrigger{subtriggers: triggers}
}

// 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() {}

View on GitHub (pinned to 12126d8942)