hashicorp/nomad · error
failed adding job %s: %v
Error message
failed adding job %s: %v
What it means
PeriodicDispatcher.Add registers (or updates) a tracked periodic job and computes its next launch time via job.Periodic.Next(). If computing the next launch time fails, the job ID and the underlying error are wrapped and returned. Called by applyUpsertJob (state apply path) and restorePeriodicDispatcher (server startup).
Source
Thrown at nomad/periodic.go:219
tuple := structs.NamespacedID{
ID: job.ID,
Namespace: job.Namespace,
}
_, tracked := p.tracked[tuple]
if disabled {
if tracked {
p.removeLocked(tuple)
}
// If the job is disabled and we aren't tracking it, do nothing.
return nil
}
// Add or update the job.
p.tracked[tuple] = job
next, err := job.Periodic.Next(time.Now().In(job.Periodic.GetLocation()))
if err != nil {
return fmt.Errorf("failed adding job %s: %v", job.NamespacedID(), err)
}
if tracked {
if err := p.heap.Update(job, next); err != nil {
return fmt.Errorf("failed to update job %q (%s) launch time: %v", job.ID, job.Namespace, err)
}
p.logger.Debug("updated periodic job", "job", job.NamespacedID())
} else {
if err := p.heap.Push(job, next); err != nil {
return fmt.Errorf("failed to add job %v: %v", job.ID, err)
}
p.logger.Debug("registered periodic job", "job", job.NamespacedID())
}
// Signal an update.
select {
case p.updateCh <- struct{}{}:
default:
}View on GitHub (pinned to 482b49bf1a)
Solutions
- Fix the job's Periodic.Spec / cron expression to a valid 5-field cron (or supported @-macro)
- Verify the job's TimeZone resolves on the server (IANA zone present in /usr/share/zoneinfo)
- Re-submit the corrected job with nomad job run; check restorePeriodicDispatcher logs for the offending job ID
- If caused by version incompatibility, migrate the job spec to the current format
Example fix
// before
periodic {
cron = "* * * *"
}
// after
periodic {
cron = "*/5 * * * *"
} Defensive patterns
Strategy: validation
Validate before calling
// validate cron and tz before job submit
cronRe := regexp.MustCompile(`(@(annually|yearly|monthly|weekly|daily|hourly|reboot))|((((\d+,)+\d+|\d+(\/\d+)?|\*|\?|JAN|FEB|...)\s+){4,5})`)
if !cronRe.MatchString(job.Periodic.Spec) { return errors.New("invalid cron spec") }
if _, err := time.LoadLocation(job.TimeZone); err != nil { return errors.New("invalid timezone") } Try / catch
err := client.Jobs().Register(job, nil, nil)
if err != nil && strings.Contains(err.Error(), "failed adding job") {
// periodic spec could not be evaluated: fix cron/tz and resubmit
} Prevention
- Validate cron expressions client-side before submit
- Use IANA timezone names that exist on servers
- Pin Nomad client/server versions to matching job spec formats
When it happens
Trigger: job.Periodic.Next(time.Now().In(job.Periodic.GetLocation())) returns an error — e.g. a cron spec the time.Next parser cannot evaluate, or an invalid/unresolvable time location after job registration or at startup restore.
Common situations: Job submitted with a malformed cron expression that passed light validation but fails at computation; timezone string (tz field) that cannot be loaded via time.LoadLocation on the server; restoring jobs at startup whose spec is incompatible with the current Nomad version.
Related errors
- must specify cron block
- failed parsing cron expression %s: %v
- failed parsing cron expression: %q
- failed parsing cron expression: %s: %v
- failed to update job %q (%s) launch time: %v
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/9068d600d46a152e.
Report an issue: GitHub.