{"record":{"id":"82937cfa3e95d01f","repo":"hashicorp/nomad","slug":"failed-adding-job-to-periodic-dispatcher-v","errorCode":null,"errorMessage":"failed adding job to periodic dispatcher: %v","messagePattern":"failed adding job to periodic dispatcher: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/fsm.go","lineNumber":706,"sourceCode":"\t\t\treturn err\n\t\t}\n\t\tif found != nil {\n\t\t\t// found a job matching the idempotency token, so bail out early\n\t\t\treturn nil\n\t\t}\n\t}\n\n\tif err := n.state.UpsertJobWithRequest(msgType, index, &req); err != nil {\n\t\tn.logger.Error(\"UpsertJob failed\", \"error\", err)\n\t\treturn err\n\t}\n\n\t// We always add the job to the periodic dispatcher because there is the\n\t// possibility that the periodic spec was removed and then we should stop\n\t// tracking it.\n\tif err := n.periodicDispatcher.Add(req.Job); err != nil {\n\t\tn.logger.Error(\"periodicDispatcher.Add failed\", \"error\", err)\n\t\treturn fmt.Errorf(\"failed adding job to periodic dispatcher: %v\", err)\n\t}\n\n\t// Create a watch set\n\tws := memdb.NewWatchSet()\n\n\t// If it is an active periodic job, record the time it was inserted. This is\n\t// necessary for recovering during leader election. It is possible that from\n\t// the time it is added to when it was suppose to launch, leader election\n\t// occurs and the job was not launched. In this case, we use the insertion\n\t// time to determine if a launch was missed.\n\tif req.Job.IsPeriodicActive() {\n\t\tprevLaunch, err := n.state.PeriodicLaunchByID(ws, req.Namespace, req.Job.ID)\n\t\tif err != nil {\n\t\t\tn.logger.Error(\"PeriodicLaunchByID failed\", \"error\", err)\n\t\t\treturn err\n\t\t}\n\n\t\t// Record the insertion time as a launch. We overload the launch table","sourceCodeStart":688,"sourceCodeEnd":724,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/fsm.go#L688-L724","documentation":"Returned by FSM applyUpsertJob when the job being upserted cannot be added to the periodic dispatcher. This is Raft-applied state, so the error fails the whole job registration even though it occurs on the periodic-tracking side step.","triggerScenarios":"n.periodicDispatcher.Add(req.Job) returns an error while applying an Job.Upsert RPC through Raft — e.g. the job is periodic but its spec/timezone cannot be parsed or scheduled.","commonSituations":"Registering a periodic job with an invalid cron expression, an unparseable timezone (TZ database missing on the server host), or a periodic spec that fails validation at dispatch time.","solutions":["Fix the job's periodic block: validate the cron expression and timezone before submitting","Ensure the server host has a valid timezone database (tzdata) installed","Retry the job registration after correcting the periodic spec"],"exampleFix":"// before\njob.TaskGroups[0].Tasks[0]. ... // periodic { cron: \"* * * * * *\", timeZone: \"Bogus/Zone\" }\n// after\nperiodic := &api.PeriodicConfig{ Spec: \"*/5 * * * *\", TimeZone: \"UTC\" }","handlingStrategy":"validation","validationCode":"if job.IsPeriodic() {\n    if _, err := cron.Parse(job.Periodic.Spec); err != nil { return fmt.Errorf(\"bad cron: %w\", err) }\n    if _, err := time.LoadLocation(job.Periodic.TimeZone); err != nil { return fmt.Errorf(\"bad tz: %w\", err) }\n}","typeGuard":"func validPeriodic(j *api.Job) bool {\n    return !j.IsPeriodic() || (j.Periodic.Spec != \"\" && j.Periodic.TimeZone != \"Bogus\")\n}","tryCatchPattern":null,"preventionTips":["Validate cron expressions and timezones client-side before job submit","Install tzdata on all Nomad servers","Use 'nomad job validate' / plan before registering periodic jobs"],"tags":["nomad","fsm","raft","periodic-job"],"backgroundTag":"periodic-job-dispatch-failed","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"}