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

  1. Verify the job definition still contains the task group: `nomad job inspect <job>`.
  2. Stop/clean up the stale allocation (`nomad alloc stop <alloc>` or remove it from the client state store) and reschedule.
  3. Resubmit the job so allocations are regenerated against the current spec.
  4. 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

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


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