apache/beam · error

trigger.AfterCount(%v) must be a positive integer

Error message

trigger.AfterCount(%v) must be a positive integer

What it means

trigger.AfterCount builds a trigger that fires after at least `count` elements. It panics with this error when count is less than 1, since a non-positive element count is meaningless for an element-count trigger. It is a fail-fast constructor guard, not a recoverable pipeline error.

Source

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

}

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

func (t AfterCountTrigger) trigger() {}

// ElementCount returns the elementCount.
func (t *AfterCountTrigger) ElementCount() int32 {
	return t.elementCount
}

// AfterCount constructs a trigger that fires after
// at least `count` number of elements are processed.
func AfterCount(count int32) *AfterCountTrigger {
	if count < 1 {
		panic(fmt.Errorf("trigger.AfterCount(%v) must be a positive integer", count))
	}
	return &AfterCountTrigger{elementCount: count}
}

// AfterProcessingTimeTrigger fires after passage of times defined in timestampTransforms.
type AfterProcessingTimeTrigger struct {
	timestampTransforms []TimestampTransform
}

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

func (t AfterProcessingTimeTrigger) trigger() {}

// TimestampTransforms returns the timestampTransforms.
func (t *AfterProcessingTimeTrigger) TimestampTransforms() []TimestampTransform {

View on GitHub (pinned to 12126d8942)

Solutions

  1. Pass a positive integer >= 1 to AfterCount.
  2. Clamp or validate the count variable before constructing the trigger.
  3. If 'fire immediately' is intended, use trigger.AfterFirst() or a default trigger instead.
  4. Check the config source feeding the count for missing/zero values.

Example fix

// before
tr := trigger.AfterCount(cfg.Count) // Count could be 0
// after
if cfg.Count < 1 { cfg.Count = 1 }
tr := trigger.AfterCount(cfg.Count)
Defensive patterns

Strategy: validation

Validate before calling

if count < 1 { return fmt.Errorf("AfterCount requires >= 1, got %d", count) }

Try / catch

defer func() {
    if r := recover(); r != nil {
        if strings.Contains(fmt.Sprint(r), "AfterCount") { return ErrInvalidTriggerCount }
        panic(r)
    }
}()

Prevention

When it happens

Trigger: Calling windowing.trigger.AfterCount(0) or AfterCount(-1) (e.g. count computed from a variable or config that defaulted to zero).

Common situations: Count loaded from an unset config/env variable defaulting to 0; off-by-one arithmetic producing 0; users assuming 0 means 'fire immediately'.

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