hashicorp/nomad · error
failed adding job to periodic dispatcher: %v
Error message
failed adding job to periodic dispatcher: %v
What it means
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.
Source
Thrown at nomad/fsm.go:706
return err
}
if found != nil {
// found a job matching the idempotency token, so bail out early
return nil
}
}
if err := n.state.UpsertJobWithRequest(msgType, index, &req); err != nil {
n.logger.Error("UpsertJob failed", "error", err)
return err
}
// We always add the job to the periodic dispatcher because there is the
// possibility that the periodic spec was removed and then we should stop
// tracking it.
if err := n.periodicDispatcher.Add(req.Job); err != nil {
n.logger.Error("periodicDispatcher.Add failed", "error", err)
return fmt.Errorf("failed adding job to periodic dispatcher: %v", err)
}
// Create a watch set
ws := memdb.NewWatchSet()
// If it is an active periodic job, record the time it was inserted. This is
// necessary for recovering during leader election. It is possible that from
// the time it is added to when it was suppose to launch, leader election
// occurs and the job was not launched. In this case, we use the insertion
// time to determine if a launch was missed.
if req.Job.IsPeriodicActive() {
prevLaunch, err := n.state.PeriodicLaunchByID(ws, req.Namespace, req.Job.ID)
if err != nil {
n.logger.Error("PeriodicLaunchByID failed", "error", err)
return err
}
// Record the insertion time as a launch. We overload the launch tableView on GitHub (pinned to 482b49bf1a)
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
Example fix
// before
job.TaskGroups[0].Tasks[0]. ... // periodic { cron: "* * * * * *", timeZone: "Bogus/Zone" }
// after
periodic := &api.PeriodicConfig{ Spec: "*/5 * * * *", TimeZone: "UTC" } Defensive patterns
Strategy: validation
Validate before calling
if job.IsPeriodic() {
if _, err := cron.Parse(job.Periodic.Spec); err != nil { return fmt.Errorf("bad cron: %w", err) }
if _, err := time.LoadLocation(job.Periodic.TimeZone); err != nil { return fmt.Errorf("bad tz: %w", err) }
} Type guard
func validPeriodic(j *api.Job) bool {
return !j.IsPeriodic() || (j.Periodic.Spec != "" && j.Periodic.TimeZone != "Bogus")
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- periodicDispatcher.Remove failed: %w
- index update failed: %v
- DeleteJob failed: %w
- JobByID lookup failed: %w
- job %q in namespace %q doesn't exist to be deregistered
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/82937cfa3e95d01f.
Report an issue: GitHub.