{"record":{"id":"8064483f4d321d06","repo":"hashicorp/nomad","slug":"can-t-evaluate-periodic-job","errorCode":null,"errorMessage":"can't evaluate periodic job","messagePattern":"can't evaluate periodic job","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/job_endpoint.go","lineNumber":718,"sourceCode":"\t\treturn fmt.Errorf(\"missing job ID for evaluation\")\n\t}\n\n\t// Lookup the job\n\tsnap, err := j.srv.fsm.State().Snapshot()\n\tif err != nil {\n\t\treturn err\n\t}\n\tws := memdb.NewWatchSet()\n\tjob, err := snap.JobByID(ws, args.RequestNamespace(), args.JobID)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif job == nil {\n\t\treturn fmt.Errorf(\"job not found\")\n\t}\n\n\tif job.IsPeriodic() {\n\t\treturn fmt.Errorf(\"can't evaluate periodic job\")\n\t} else if job.IsParameterized() {\n\t\treturn fmt.Errorf(\"can't evaluate parameterized job\")\n\t}\n\n\tforceRescheduleAllocs := make(map[string]*structs.DesiredTransition)\n\n\tif args.EvalOptions.ForceReschedule {\n\t\t// Find any failed allocs that could be force rescheduled\n\t\tallocs, err := snap.AllocsByJob(ws, args.RequestNamespace(), args.JobID, false)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfor _, alloc := range allocs {\n\t\t\ttaskGroup := job.LookupTaskGroup(alloc.TaskGroup)\n\t\t\t// Forcing rescheduling is only allowed if task group has rescheduling enabled\n\t\t\tif taskGroup == nil || !taskGroup.ReschedulePolicy.Enabled() {\n\t\t\t\tcontinue","sourceCodeStart":700,"sourceCodeEnd":736,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/job_endpoint.go#L700-L736","documentation":"The Job.Evaluate RPC refuses to force an evaluation on a periodic job. Periodic jobs generate child dispatch jobs on their schedule; forcing an evaluation on the parent has no defined meaning, so Nomad rejects it explicitly via job.IsPeriodic().","triggerScenarios":"POST /v1/job/<id>/evaluate with the ID of a job whose Periodic block is set (a periodic parent job), e.g. running 'nomad job eval' or calling Evaluate on the parent instead of a spawned child run.","commonSituations":"Automation iterating over all jobs and calling Evaluate on each, hitting periodic parents; operators trying to 're-run' a periodic job by evaluating it instead of using force/periodic force endpoints.","solutions":["Evaluate the periodic child job (e.g. <parent>/<timestamp>) instead of the parent","Use the periodic force endpoint POST /v1/job/<id>/periodic/force to trigger a run now","Filter periodic jobs out of bulk-evaluation automation (check job.Periodic != nil client-side)","Adjust the schedule in the job spec if a run is needed at a different time"],"exampleFix":"// before\nfor _, j := range jobs { client.Jobs().Evaluate(j.ID, nil) }\n// after\nfor _, j := range jobs {\n    if j.Periodic != nil { continue }\n    client.Jobs().Evaluate(j.ID, nil)\n}","handlingStrategy":"validation","validationCode":"job, _, err := client.Jobs().Info(jobID, nil)\nif err != nil { return err }\nif job.Periodic != nil {\n\treturn fmt.Errorf(\"%s is periodic; dispatch/force a child instead\", jobID)\n}","typeGuard":"func isPeriodicParent(j *api.Job) bool { return j != nil && j.Periodic != nil }","tryCatchPattern":"if _, _, err := client.Jobs().Evaluate(jobID, nil); err != nil && strings.Contains(err.Error(), \"can't evaluate periodic\") {\n\t_, _, err = client.Jobs().ForcePeriodic(jobID, nil)\n}","preventionTips":["Skip jobs with Periodic set in bulk evaluation loops","Use POST /v1/job/<id>/periodic/force to trigger periodic runs","Evaluate spawned child jobs, never the parent template"],"tags":["nomad","periodic-job","unsupported-operation"],"backgroundTag":"unsupported-operation","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"}