{"record":{"id":"a75389c74a526151","repo":"hashicorp/nomad","slug":"must-specify-cron-block","errorCode":null,"errorMessage":"must specify cron block","messagePattern":"must specify cron block","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/task_sched.go","lineNumber":67,"sourceCode":"\tTaskScheduleStateRun        TaskScheduleState = \"\"\n\tTaskScheduleStateForceRun   TaskScheduleState = \"force_run\"\n\tTaskScheduleStateSchedPause TaskScheduleState = \"scheduled_pause\"\n\tTaskScheduleStateForcePause TaskScheduleState = \"force_pause\"\n\t// TaskScheduleStateSchedResume is a transitory state that will become\n\t// either SchedPause or (sched) Run\n\tTaskScheduleStateSchedResume TaskScheduleState = \"schedule_resume\"\n)\n\n// TaskSchedule allows specifying a time based execution schedule for tasks.\n//\n// Enterprise only.\ntype TaskSchedule struct {\n\tCron *TaskScheduleCron\n}\n\nfunc (t *TaskSchedule) Validate() error {\n\tif t.Cron == nil {\n\t\treturn errors.New(\"must specify cron block\")\n\t}\n\n\tconst (\n\t\tstartFields     = 6\n\t\tendFields       = 2\n\t\trestrictedChars = \"/,\"\n\t)\n\n\tif strings.Count(t.Cron.Start, \" \") != (startFields - 1) {\n\t\treturn fmt.Errorf(\"cron.start must contain %d fields\", startFields)\n\t}\n\tif strings.Count(t.Cron.End, \" \") != (endFields - 1) {\n\t\treturn fmt.Errorf(\"cron.end must contain %d fields\", endFields)\n\t}\n\tif strings.ContainsAny(t.Cron.Start, restrictedChars) {\n\t\treturn fmt.Errorf(\"cron.start must not contain %q\", restrictedChars)\n\t}\n\tif strings.ContainsAny(t.Cron.End, restrictedChars) {","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/task_sched.go#L49-L85","documentation":"TaskSchedule.Validate requires a cron block: a TaskSchedule with a nil Cron field is structurally invalid, so validation stops immediately with \"must specify cron block\". The schedule is defined entirely by its TaskScheduleCron expression, so without it there is nothing to evaluate.","triggerScenarios":"Constructing or submitting a task schedule (e.g. in a Nomad task scheduler/variable-related schedule stanza) with the schedule block present but no cron child block; programmatically creating structs.TaskSchedule{} without setting Cron.","commonSituations":"Hand-written HCL where the cron stanza was omitted or misnamed; tests and tooling building TaskSchedule literals; partial config merges that dropped the cron section.","solutions":["Add a cron block with a valid cron expression inside the schedule stanza.","If no schedule is intended, omit the whole schedule block rather than emitting an empty one.","Fix HCL block naming so the cron section parses into t.Cron instead of being ignored."],"exampleFix":"// before (HCL)\nschedule {\n}\n// after\nschedule {\n  cron = \"0 2 * * *\"\n}","handlingStrategy":"validation","validationCode":"func validSchedule(t *structs.TaskSchedule) bool {\n\treturn t != nil && t.Cron != nil\n}\nif !validSchedule(sched) {\n\treturn errors.New(\"schedule requires a cron block\")\n}","typeGuard":"func hasCron(t *structs.TaskSchedule) bool { return t != nil && t.Cron != nil }","tryCatchPattern":"if err := sched.Validate(); err != nil && strings.Contains(err.Error(), \"must specify cron\") {\n\t// fix the config: add a cron block before resubmitting\n}","preventionTips":["Always include a cron block when writing a schedule stanza","Omit the schedule block entirely when no schedule is needed","Lint HCL so misnamed cron blocks are caught before submit"],"tags":["nomad","validation","cron","scheduling"],"backgroundTag":"missing-required-argument","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"}