{"record":{"id":"2261b5e45276bf7d","repo":"hashicorp/nomad","slug":"failed-parsing-cron-expression-s-v","errorCode":null,"errorMessage":"failed parsing cron expression %s: %v","messagePattern":"failed parsing cron expression (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"api/jobs.go","lineNumber":943,"sourceCode":"\n// Next returns the closest time instant matching the spec that is after the\n// passed time. If no matching instance exists, the zero value of time.Time is\n// returned. The `time.Location` of the returned value matches that of the\n// passed time.\nfunc (p *PeriodicConfig) Next(fromTime time.Time) (time.Time, error) {\n\t// Single spec parsing\n\tif p != nil && *p.SpecType == PeriodicSpecCron {\n\t\tif p.Spec != nil && *p.Spec != \"\" {\n\t\t\treturn cronParseNext(fromTime, *p.Spec)\n\t\t}\n\t}\n\n\t// multiple specs parsing\n\tvar nextTime time.Time\n\tfor _, spec := range p.Specs {\n\t\tt, err := cronParseNext(fromTime, spec)\n\t\tif err != nil {\n\t\t\treturn time.Time{}, fmt.Errorf(\"failed parsing cron expression %s: %v\", spec, err)\n\t\t}\n\t\tif nextTime.IsZero() || t.Before(nextTime) {\n\t\t\tnextTime = t\n\t\t}\n\t}\n\treturn nextTime, nil\n}\n\n// cronParseNext is a helper that parses the next time for the given expression\n// but captures any panic that may occur in the underlying library.\n// ---  THIS FUNCTION IS REPLICATED IN nomad/structs/structs.go\n// and should be kept in sync.\nfunc cronParseNext(fromTime time.Time, spec string) (t time.Time, err error) {\n\tdefer func() {\n\t\tif recover() != nil {\n\t\t\tt = time.Time{}\n\t\t\terr = fmt.Errorf(\"failed parsing cron expression: %q\", spec)\n\t\t}","sourceCodeStart":925,"sourceCodeEnd":961,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/api/jobs.go#L925-L961","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Validate the cron spec locally with the cronexpr library or `nomad job run -output` before submitting","Use Nomad's 6-field (with seconds) cron format; check field ranges","Fix the offending spec named in the error message","Wrap cronParseNext calls in recovery-aware validation at config load time"],"exampleFix":"// before\nspec = \"0 * * *\"   // too few fields\n// after\nspec = \"0 * * * * *\" // valid 6-field Nomad cron","handlingStrategy":"validation","validationCode":"for _, spec := range specs {\n    if _, err := cronexpr.Parse(spec); err != nil {\n        return fmt.Errorf(\"invalid cron spec %q: %v\", spec, err)\n    }\n}","typeGuard":null,"tryCatchPattern":"next, err := periodic.Next(time.Now())\nif err != nil {\n    var pe *time.ParseError\n    _ = pe\n    return fmt.Errorf(\"job periodic config rejected: %w\", err)\n}","preventionTips":["Use Nomad's 6-field cron format with seconds","Lint job files for cron specs in CI before nomad job run","Keep field values within valid ranges (month 1-12, dom 1-31)"],"tags":["cron","validation","periodic-jobs"],"backgroundTag":"invalid-cron-expression","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}