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

  1. Sanitize/validate the spec string before storing it in the job config
  2. Test the spec against cronexpr.Parse in isolation to reproduce the panic
  3. Upgrade Nomad/cronexpr for panic fixes
  4. 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

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


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