hashicorp/nomad · error

failed parsing cron expression %s: %v

Error message

failed parsing cron expression %s: %v

What it means

PeriodicConfig.Next (multi-spec path) computes the next launch time for each cron spec via cronParseNext. If any individual spec fails to parse or evaluate, the error is wrapped as 'failed parsing cron expression %s: %v' naming the offending spec. This is the exported wrapper for the underlying cronexpr failure or panic.

Source

Thrown at api/jobs.go:943

// Next returns the closest time instant matching the spec that is after the
// passed time. If no matching instance exists, the zero value of time.Time is
// returned. The `time.Location` of the returned value matches that of the
// passed time.
func (p *PeriodicConfig) Next(fromTime time.Time) (time.Time, error) {
	// Single spec parsing
	if p != nil && *p.SpecType == PeriodicSpecCron {
		if p.Spec != nil && *p.Spec != "" {
			return cronParseNext(fromTime, *p.Spec)
		}
	}

	// multiple specs parsing
	var nextTime time.Time
	for _, spec := range p.Specs {
		t, err := cronParseNext(fromTime, spec)
		if err != nil {
			return time.Time{}, fmt.Errorf("failed parsing cron expression %s: %v", spec, err)
		}
		if nextTime.IsZero() || t.Before(nextTime) {
			nextTime = t
		}
	}
	return nextTime, nil
}

// cronParseNext is a helper that parses the next time for the given expression
// but captures any panic that may occur in the underlying library.
// ---  THIS FUNCTION IS REPLICATED IN nomad/structs/structs.go
// and should be kept in sync.
func cronParseNext(fromTime time.Time, spec string) (t time.Time, err error) {
	defer func() {
		if recover() != nil {
			t = time.Time{}
			err = fmt.Errorf("failed parsing cron expression: %q", spec)
		}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Validate the cron spec locally with the cronexpr library or `nomad job run -output` before submitting
  2. Use Nomad's 6-field (with seconds) cron format; check field ranges
  3. Fix the offending spec named in the error message
  4. Wrap cronParseNext calls in recovery-aware validation at config load time

Example fix

// before
spec = "0 * * *"   // too few fields
// after
spec = "0 * * * * *" // valid 6-field Nomad cron
Defensive patterns

Strategy: validation

Validate before calling

for _, spec := range specs {
    if _, err := cronexpr.Parse(spec); err != nil {
        return fmt.Errorf("invalid cron spec %q: %v", spec, err)
    }
}

Try / catch

next, err := periodic.Next(time.Now())
if err != nil {
    var pe *time.ParseError
    _ = pe
    return fmt.Errorf("job periodic config rejected: %w", err)
}

Prevention

When it happens

Trigger: Registering/updating a periodic job whose 'spec' (or one of multiple specs) is an invalid cron expression, or whose spec panics cronexpr during Next evaluation.

Common situations: Typos like '0 25 25 * * *' (invalid day), 5-field specs given to a parser expecting 6-field Nomad specs, timezone-naive expressions, hand-edited HCL/JSON with garbage specs.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/2261b5e45276bf7d. Report an issue: GitHub.