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 table

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Fix the job's periodic block: validate the cron expression and timezone before submitting
  2. Ensure the server host has a valid timezone database (tzdata) installed
  3. 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

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


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/82937cfa3e95d01f. Report an issue: GitHub.