temporalio/temporal · error

schedule spec next-time search exceeded the compute iteratio

Error message

schedule spec next-time search exceeded the compute iteration limit

What it means

ErrComputeLimitExceeded is returned by GetNextTime when searching for the next schedule spec occurrence (skipping excluded times) exceeds a hard iteration bound configured via warnIterations/maxIterations. It guards against specs (e.g. calendars with many exclusion blocks or extremely tight intervals) that would otherwise consume unbounded CPU in the scheduler workflow.

Source

Thrown at service/worker/scheduler/spec.go:60

		// locationCache is a cache for the results of time.LoadLocation. That function accesses
		// the filesystem and is relatively slow. We assume that it returns a semantically
		// equivalent value for the same location name. This isn't strictly true, for example if
		// the time zone database is changed while the process is running. To handle that, we
		// expire entries after a day. Note that we cache negative results also.
		locationCache  cache.Cache
		warnIterations dynamicconfig.IntPropertyFn
		maxIterations  dynamicconfig.IntPropertyFn
	}

	locationAndError struct {
		loc *time.Location
		err error
	}
)

// ErrComputeLimitExceeded is returned by GetNextTime when the search for the next matching time
// hits the hard compute iteration bound before finding a non-excluded time.
var ErrComputeLimitExceeded = errors.New("schedule spec next-time search exceeded the compute iteration limit")
var ErrScheduleSpecLimitHit = serviceerror.NewInvalidArgument("the schedule calendar specification has too many exclusions. Please modify the specification.")

// NewSpecBuilder takes the compute-limit getters directly (rather than a *dynamicconfig.Collection)
// so the dynamic-config plumbing stays in the wiring layer, per the common codebase pattern.
func NewSpecBuilder(warnIterations, maxIterations dynamicconfig.IntPropertyFn) *SpecBuilder {
	return &SpecBuilder{
		warnIterations: warnIterations,
		maxIterations:  maxIterations,
		locationCache: cache.New(1000,
			&cache.Options{
				TTL: 24 * time.Hour,
			},
		),
	}
}

func (b *SpecBuilder) NewCompiledSpec(spec *schedulepb.ScheduleSpec) (*CompiledSpec, error) {
	spec, err := canonicalizeSpec(spec)

View on GitHub (pinned to bde624efd1)

Solutions

  1. Simplify the schedule spec: reduce the number of exclusion intervals or replace many calendar entries with fewer broader ones.
  2. Increase the scheduler spec compute limit dynamic config values (warnIterations / maxIterations) if the spec is legitimate but complex.
  3. Narrow exclusion windows so the next-time search finds a match faster.
  4. Reproduce locally with TestGetNextTimeComputeLimitExceeded-style iteration counts to confirm which part of the spec drives the search past the limit.

Example fix

// before
maxIterations := dc.GetIntPropertyFn(dynamicconfig.SchedulerSpecComputeMaxIterations) // e.g. 1000, too low for complex spec
// after
maxIterations := dc.GetIntPropertyFn(dynamicconfig.SchedulerSpecComputeMaxIterations) // raised to 100000 for this namespace
// or reduce spec complexity: collapse 50 exclusion ranges into 3
Defensive patterns

Strategy: validation

Validate before calling

// before scheduling, sanity-check spec complexity
if len(spec.ExcludeCalendar)+len(spec.ExcludeTimes) > 100 {
    return fmt.Errorf("spec has %d exclusions; risk of compute-limit failure", len(spec.ExcludeCalendar)+len(spec.ExcludeTimes))
}

Try / catch

result, err := GetNextTime(...)
if errors.Is(err, scheduler.ErrComputeLimitExceeded) {
    // alert: spec too complex; simplify exclusions or raise dynamic config limit
}

Prevention

When it happens

Trigger: GetNextTime / checkNextScheduleResult is called with a schedule spec whose next matching time cannot be found within maxIterations iterations — typically a calendar spec combined with large exclusion ranges, or an interval spec with a phase that pushes matches far into excluded periods.

Common situations: Schedules built programmatically with many calendar entries and broad ExcludeCalendar lists; timezone/DST edge cases generating long gap searches; misconfigured maxIterations dynamic config set too low for legitimate specs; long blocked periods (maintenance windows) covering many candidate times.

Related errors


AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01). Data as JSON: /api/errors/9decb3f4074f044e. Report an issue: GitHub.