hashicorp/nomad · error
failed parsing cron expression: %q
Error message
failed parsing cron expression: %q
What it means
CronParseNext wraps cronexpr evaluation and recovers panics from the underlying library, converting a recovered panic into this error carrying the offending spec in %q. It exists because cronexpr can panic on certain expressions during Next() evaluation even after a successful parse.
Source
Thrown at nomad/structs/structs.go:5971
}
func (p *PeriodicConfig) Canonicalize() {
// Load the location
l, err := time.LoadLocation(p.TimeZone)
if err != nil {
p.location = time.UTC
}
p.location = l
}
// CronParseNext is a helper that parses the next time for the given expression
// but captures any panic that may occur in the underlying library.
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)
}
}()
exp, err := cronexpr.Parse(spec)
if err != nil {
return time.Time{}, fmt.Errorf("failed parsing cron expression: %s: %v", spec, err)
}
return exp.Next(fromTime), nil
}
// 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) {
switch p.SpecType {
case PeriodicSpecCron:
// Single spec parsing
if p.Spec != "" {View on GitHub (pinned to 482b49bf1a)
Solutions
- Simplify the cron expression (avoid exotic dom/dow combinations) and resubmit the job.
- Check the cronexpr library version for known panic bugs and upgrade Nomad/library.
- Catch the error and fall back to a simpler, well-tested spec like "*/5 * * * *".
- If reproducible, validate the spec with a standalone cronexpr.Parse + Next harness before scheduling.
Example fix
// before t, err := structs.CronParseNext(now, "0 0 31 2 *") // pathological: Feb 31 // after t, err := structs.CronParseNext(now, "0 0 1 2 *")
Defensive patterns
Strategy: try-catch
Validate before calling
// pre-parse to catch errors without triggering the panic path:
if _, err := cronexpr.Parse(spec); err != nil {
return fmt.Errorf("spec unusable: %w", err)
} Try / catch
t, err := structs.CronParseNext(now, spec)
if err != nil && strings.HasPrefix(err.Error(), "failed parsing cron expression") {
t = now.Add(defaultInterval) // fallback schedule
} Prevention
- Always check the error return of CronParseNext; it may indicate a library panic.
- Prefer simple specs over exotic dom/dow combinations.
- Upgrade Nomad/cronexpr when panic bugs are fixed upstream.
- Test periodic jobs in dev with representative evaluation times.
When it happens
Trigger: Calling structs.CronParseNext(fromTime, spec) where the cronexpr library panics while computing the next fire time (e.g. some pathological expressions or nil-internal states).
Common situations: Periodic job dispatch/evaluation at runtime computing the next launch time; expressions that parsed fine at validation but panic during iteration; unusual calendar tokens (dom/dow combos) triggering upstream bugs.
Related errors
- failed parsing cron expression: %s: %v
- failed parsing cron expression %s: %v
- eval broker is enabled; eval broker must be paused to delete
- eval broker is enabled; eval broker must be paused to delete
- Job registration, dispatch, and scale are disabled by the sc
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/bf10d89e0c3d8473.
Report an issue: GitHub.