hashicorp/nomad · error

Invalid cron spec %q: %v

Error message

Invalid cron spec %q: %v

What it means

PeriodicConfig.Validate parses the job's single cron Spec with the cronexpr library when SpecType is PeriodicSpecCron. If cronexpr.Parse returns an error for the expression, the error is wrapped and appended to the validation multierror. The expression never evaluated, so the job cannot be scheduled periodically.

Source

Thrown at nomad/structs/structs.go:5936

		_ = multierror.Append(&mErr, fmt.Errorf("Only cron or crons may be used"))
	}
	if p.Spec == "" && len(p.Specs) == 0 {
		_ = multierror.Append(&mErr, fmt.Errorf("Must specify a spec"))
	}

	// Check if we got a valid time zone
	if p.TimeZone != "" {
		if _, err := time.LoadLocation(p.TimeZone); err != nil {
			_ = multierror.Append(&mErr, fmt.Errorf("Invalid time zone %q: %v", p.TimeZone, err))
		}
	}

	switch p.SpecType {
	case PeriodicSpecCron:
		// Validate the cron spec
		if p.Spec != "" {
			if _, err := cronexpr.Parse(p.Spec); err != nil {
				_ = multierror.Append(&mErr, fmt.Errorf("Invalid cron spec %q: %v", p.Spec, err))
			}
		}
		// Validate the cron specs
		for _, spec := range p.Specs {
			if _, err := cronexpr.Parse(spec); err != nil {
				_ = multierror.Append(&mErr, fmt.Errorf("Invalid cron spec %q: %v", spec, err))
			}
		}

	case PeriodicSpecTest:
		// No-op
	default:
		_ = multierror.Append(&mErr, fmt.Errorf("Unknown periodic specification type %q", p.SpecType))
	}

	return mErr.ErrorOrNil()
}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Fix the cron expression to a valid cronexpr-parseable spec (5 fields: min hour dom mon dow), e.g. "*/15 * * * *".
  2. Test the expression locally with cronexpr.Parse or an online cron validator before submitting.
  3. If multiple schedules are needed, move them into the Specs list, each individually valid.
  4. Verify spec_type is actually "cron" so the expression is parsed with the right grammar.

Example fix

// before
periodic {
  spec = "0 9 * * MON-FRI extra"
}
// after
periodic {
  spec = "0 9 * * MON-FRI"
}
Defensive patterns

Strategy: validation

Validate before calling

import "github.com/hashicorp/cronexpr"

func validCron(spec string) bool {
    _, err := cronexpr.Parse(spec)
    return err == nil
}
// call before submitting: if !validCron(job.Periodic.Spec) { ... }

Try / catch

t, err := structs.CronParseNext(time.Now(), spec)
if err != nil {
    log.Printf("bad cron spec %q: %v", spec, err)
    // fall back or fix input
}

Prevention

When it happens

Trigger: Submitting a periodic job with `periodic { spec = "...", spec_type = "cron" }` where the cron expression fails cronexpr.Parse — e.g. "* * *" (too few fields), "*/abc * * * *", or stray words.

Common situations: Copy-pasting cron expressions from systems with different dialects (e.g. 5-field vs Quartz 6-field); typos in step values; using @daily-style descriptors not supported by cronexpr.

Related errors


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