hashicorp/nomad · error
failed parsing cron expression: %q
Error message
failed parsing cron expression: %q
What it means
cronParseNext recovers panics from the cronexpr library and converts them into this error ('failed parsing cron expression: %q'), quoting the whole spec. cronexpr is known to panic on some malformed inputs, so the deferred recover guards callers of PeriodicConfig.Next from crashing. This copy lives in api/jobs.go and is replicated in nomad/structs.
Source
Thrown at api/jobs.go:960
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)
}
}()
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
}
func (p *PeriodicConfig) GetLocation() (*time.Location, error) {
if p.TimeZone == nil || *p.TimeZone == "" {
return time.UTC, nil
}
return time.LoadLocation(*p.TimeZone)
}
// ParameterizedJobConfig is used to configure the parameterized job.View on GitHub (pinned to 482b49bf1a)
Solutions
- Sanitize/validate the spec string before storing it in the job config
- Test the spec against cronexpr.Parse in isolation to reproduce the panic
- Upgrade Nomad/cronexpr for panic fixes
- Fix the malformed field values (day-of-month 0, month 13, etc.)
Example fix
// before spec = "* * * 13 * *" // month 13 → panic in cronexpr // after spec = "* * * 12 * *"
Defensive patterns
Strategy: validation
Validate before calling
func validateCronSpecSafe(spec string) (ok bool) {
defer func() { _ = recover() }()
exp, err := cronexpr.Parse(spec)
if err != nil {
return false
}
exp.Next(time.Now())
return true
} Try / catch
t, err := cronParseNext(time.Now(), spec)
if err != nil && strings.HasPrefix(err.Error(), "failed parsing cron expression") {
return ErrBadPeriodicConfig
} Prevention
- Run spec validation through a panic-guarded parser at config load
- Reject user-supplied specs before they reach job registration
- Test unusual specs against the exact cronexpr version Nomad embeds
When it happens
Trigger: A cron spec causes cronexpr.Parse or exp.Next to panic — typically deeply malformed specs, e.g. out-of-range values or pathological expressions.
Common situations: User-supplied periodic job specs from untrusted config; specs mutated programmatically; specs that pass Parse but panic on Next in certain cronexpr versions.
Related errors
- failed parsing cron expression %s: %v
- failed parsing cron expression: %s: %v
- failed adding job %s: %v
- failed parsing cron expression: %q
- must specify cron block
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/f81967d9f061eb6f.
Report an issue: GitHub.