hashicorp/nomad · error
task group %q does not exist in job %q
Error message
task group %q does not exist in job %q
What it means
The health_hook's init looks up the allocation's task group in the job struct via Job.LookupTaskGroup. If the group name recorded on the allocation doesn't exist in the job definition, the hook cannot build its health watches and returns this error during Prerun or Update.
Source
Thrown at client/allocrunner/health_hook.go:138
func (h *allocHealthWatcherHook) Name() string {
return "alloc_health_watcher"
}
// init starts the allochealth.Tracker and watchHealth goroutine on either
// Prerun or Update. Caller must set/update alloc and logger fields.
//
// Not threadsafe so the caller should lock since Updates occur concurrently.
func (h *allocHealthWatcherHook) init(allocEnv *taskenv.TaskEnv) error {
// No need to watch health as it's already set
if h.healthSetter.HasHealth() {
h.logger.Trace("not watching; already has health set")
return nil
}
tg := h.alloc.Job.LookupTaskGroup(h.alloc.TaskGroup)
if tg == nil {
return fmt.Errorf("task group %q does not exist in job %q", h.alloc.TaskGroup, h.alloc.Job.ID)
}
h.isDeploy = h.alloc.DeploymentID != ""
// No need to watch allocs for deployments that rely on operators
// manually setting health
if h.isDeploy && (tg.Update.IsEmpty() || tg.Update.HealthCheck == structs.UpdateStrategyHealthCheck_Manual) {
return nil
}
// Define the deadline, health method, min healthy time from the
// deployment if this is a deployment; otherwise from the migration
// strategy.
deadline, useChecks, minHealthyTime := getHealthParams(time.Now(), tg, h.isDeploy)
// Create a context that is canceled when the tracker should shutdown.
ctx := context.Background()
ctx, h.cancelFn = context.WithCancel(ctx)View on GitHub (pinned to 482b49bf1a)
Solutions
- Verify the job definition still contains the task group: `nomad job inspect <job>`.
- Stop/clean up the stale allocation (`nomad alloc stop <alloc>` or remove it from the client state store) and reschedule.
- Resubmit the job so allocations are regenerated against the current spec.
- If it recurs after client restarts, check the client data_dir state store for corruption and restore from a clean state.
Defensive patterns
Strategy: validation
Validate before calling
if alloc.Job.LookupTaskGroup(alloc.TaskGroup) == nil {
return fmt.Errorf("task group %q missing from job %q; resubmit job", alloc.TaskGroup, alloc.Job.ID)
} Type guard
func taskGroupExists(job *structs.Job, name string) bool {
return job != nil && job.LookupTaskGroup(name) != nil
} Try / catch
if err := hook.Prerun(); err != nil && strings.Contains(err.Error(), "does not exist in job") {
// stale alloc: stop it and reschedule a fresh allocation
} Prevention
- Resubmit jobs after renaming/removing task groups.
- Clean stale allocations from the client state store after job edits.
- Avoid manually editing client state files.
- Use nomad alloc stop for orphaned allocations rather than deleting state directly.
When it happens
Trigger: h.alloc.TaskGroup is not found among h.alloc.Job.TaskGroups — the allocation's stored job has no task group matching alloc.TaskGroup.
Common situations: Corrupted or truncated allocation state in the client state store; job submissions that renamed/removed task groups while stale allocations exist; manually edited state store data; bugs in job-serialization during client restore.
Related errors
- can't cancel terminal deployment
- can't fail terminal deployment
- can't pause terminal deployment
- can't promote terminal deployment
- can't resume terminal deployment
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/1751e57d0a89fe1c.
Report an issue: GitHub.