hashicorp/nomad · error

Task group %s validation failed: %v

Error message

Task group %s validation failed: %v

What it means

This error is produced by Job.Validate in nomad/structs/structs.go when one of a job's task groups fails its own TaskGroup.Validate check. Nomad wraps the group-level validation error in a 'Task group %s validation failed: %v' message and appends it to a multi-error, so the inner %v carries the actual rule that was violated (e.g. missing task, bad count, invalid update block).

Source

Thrown at nomad/structs/structs.go:4849

		} else {
			taskGroups[tg.Name] = idx
		}

		if tg.ShutdownDelay != nil && *tg.ShutdownDelay < 0 {
			mErr.Errors = append(mErr.Errors, errors.New("ShutdownDelay must be a positive value"))
		}

		if j.Type == "system" && tg.Count > 1 {
			mErr.Errors = append(mErr.Errors,
				fmt.Errorf("Job task group %s has count %d. Count cannot exceed 1 with system scheduler",
					tg.Name, tg.Count))
		}
	}

	// Validate the task group
	for _, tg := range j.TaskGroups {
		if err := tg.Validate(j); err != nil {
			outer := fmt.Errorf("Task group %s validation failed: %v", tg.Name, err)
			mErr.Errors = append(mErr.Errors, outer)
		}
	}

	// Validate periodic is only used with batch or sysbatch jobs.
	if j.IsPeriodic() && j.Periodic.Enabled {
		if j.Type != JobTypeBatch && j.Type != JobTypeSysBatch {
			mErr.Errors = append(mErr.Errors, fmt.Errorf(
				"Periodic can only be used with %q or %q scheduler", JobTypeBatch, JobTypeSysBatch,
			))
		}

		if err := j.Periodic.Validate(); err != nil {
			mErr.Errors = append(mErr.Errors, err)
		}
	}

	if j.IsParameterized() {

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Read the inner %v text after the colon — it names the actual group-level rule that failed.
  2. Run `nomad job validate <file>` locally to get the full multi-error list before submitting.
  3. Fix the offending stanza in the named task group (count, tasks, network, update, etc.).
  4. If the spec is generated, add a pre-submit validation step using the same structs.Job.Validate path.

Example fix

// before
job.TaskGroups = []*TaskGroup{{Name: "web"}} // no tasks
// after
job.TaskGroups = []*TaskGroup{{Name: "web", Count: 1, Tasks: []*Task{{Name: "server", Driver: "docker", Config: map[string]interface{}{"image": "nginx"}}}}}
Defensive patterns

Strategy: validation

Validate before calling

// Pre-submit check mirroring nomad job validate
for _, tg := range job.TaskGroups {
    if len(tg.Tasks) == 0 {
        return fmt.Errorf("task group %q has no tasks", tg.Name)
    }
}
if err := job.Validate(); err != nil { return err }

Prevention

When it happens

Trigger: Submitting or validating a job spec (via `nomad job run`, `nomad job validate`, API /v1/jobs, or CLI commands like job allocs that validate) where at least one TaskGroups[] entry fails Validate — e.g. a group with no tasks, negative count, overlapping ports, or invalid restart/update stanza.

Common situations: Hand-edited HCL/JSON job files; templates generating job specs; CI pipelines submitting jobs without running `nomad job validate` first; API clients constructing structs.Job structs directly and omitting required group fields.

Related errors


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