{"record":{"id":"53ac00179ff208dd","repo":"hashicorp/nomad","slug":"failed-to-update-job-q-s-launch-time-v","errorCode":null,"errorMessage":"failed to update job %q (%s) launch time: %v","messagePattern":"failed to update job %q \\((.+?)\\) launch time: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"nomad/periodic.go","lineNumber":223,"sourceCode":"\t_, tracked := p.tracked[tuple]\n\tif disabled {\n\t\tif tracked {\n\t\t\tp.removeLocked(tuple)\n\t\t}\n\n\t\t// If the job is disabled and we aren't tracking it, do nothing.\n\t\treturn nil\n\t}\n\n\t// Add or update the job.\n\tp.tracked[tuple] = job\n\tnext, err := job.Periodic.Next(time.Now().In(job.Periodic.GetLocation()))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed adding job %s: %v\", job.NamespacedID(), err)\n\t}\n\tif tracked {\n\t\tif err := p.heap.Update(job, next); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to update job %q (%s) launch time: %v\", job.ID, job.Namespace, err)\n\t\t}\n\t\tp.logger.Debug(\"updated periodic job\", \"job\", job.NamespacedID())\n\t} else {\n\t\tif err := p.heap.Push(job, next); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to add job %v: %v\", job.ID, err)\n\t\t}\n\t\tp.logger.Debug(\"registered periodic job\", \"job\", job.NamespacedID())\n\t}\n\n\t// Signal an update.\n\tselect {\n\tcase p.updateCh <- struct{}{}:\n\tdefault:\n\t}\n\n\treturn nil\n}\n","sourceCodeStart":205,"sourceCodeEnd":241,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/periodic.go#L205-L241","documentation":"When the job was already tracked, Add updates its position in the launch-time heap via p.heap.Update(job, next). If the heap update fails (job no longer present or heap invariant issues), the job ID, namespace, and error are wrapped and returned.","triggerScenarios":"p.heap.Update fails for an already-tracked job — typically a race where the job was removed from the heap concurrently (deregistration, periodic dispatch removal) between the tracked check and the Update call.","commonSituations":"Job deregistered by another request while an upsert for the same job is being applied; concurrent state-store applies racing the periodic dispatcher during leader handoff.","solutions":["Retry the job registration — the race is usually transient","Check for concurrent deregistration of the same periodic job in logs","Serialize job updates through the leader's state apply path (default) rather than direct dispatcher access","If it recurs at startup, inspect restorePeriodicDispatcher ordering and leader election churn"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"err := client.Jobs().Register(job, nil, nil)\nif err != nil && strings.Contains(err.Error(), \"failed to update job\") {\n    // transient heap race: brief wait and retry registration\n    time.Sleep(time.Second); err = client.Jobs().Register(job, nil, nil)\n}","preventionTips":["Avoid deregistering and re-registering the same periodic job concurrently","Retry transient registration failures with backoff","Watch for leader flaps that race the periodic dispatcher"],"tags":["periodic-jobs","heap","race-condition","scheduling"],"backgroundTag":"periodic-job-heap-update-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"}