hashicorp/nomad · error

Action validation failed

Error message

Action %s validation failed: %s

What it means

Task.Validate wraps each action (task event handler) validation failure as "Action %s validation failed: %s" and appends it to the multi-error. Action.Validate checks the action's name and command fields. It surfaces through job validation and CLI error output.

Solutions

  1. Read the wrapped inner error to identify the bad action field
  2. Set a valid non-empty `command` and a well-formed `name` on the action block
  3. Run `nomad job validate` on the job file before submitting

Example fix

// before
action "restart" {
}
// after
action "restart" {
  command = "/bin/restart.sh"
}
Defensive patterns

Strategy: validation

Validate before calling

for _, a := range task.Actions {
    if err := a.Validate(); err != nil {
        return fmt.Errorf("action %q: %w", a.Name, err)
    }
}

Type guard

func actionValid(a *structs.TaskAction) bool { return a.Validate() == nil }

Try / catch

if err := job.Validate(); err != nil {
    if strings.Contains(err.Error(), "Action ") && strings.Contains(err.Error(), "validation failed") { /* fix action fields */ }
}

Prevention

When it happens

Trigger: A job task defines an `action` block whose Validate fails: empty or malformed name, empty command, or other invalid action fields.

Common situations: Omitting the action's `command`; using a name with invalid characters; HCL templating producing an empty command string; upgrading jobs between Nomad versions where action validation tightened.

Related errors


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

Appendix: source

Thrown at nomad/structs/structs.go:8351

	for idx, tmpl := range t.Templates {
		if err := tmpl.Validate(); err != nil {
			outer := fmt.Errorf("Template %d validation failed: %s", idx+1, err)
			mErr.Errors = append(mErr.Errors, outer)
		}

		if other, ok := destinations[tmpl.DestPath]; ok {
			outer := fmt.Errorf("Template %d has same destination as %d", idx+1, other)
			mErr.Errors = append(mErr.Errors, outer)
		} else {
			destinations[tmpl.DestPath] = idx + 1
		}
	}

	// Validate actions.
	actions := make(map[string]bool)
	for _, action := range t.Actions {
		if err := action.Validate(); err != nil {
			outer := fmt.Errorf("Action %s validation failed: %s", action.Name, err)
			mErr.Errors = append(mErr.Errors, outer)
		}

		if handled, seen := actions[action.Name]; seen && !handled {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("Action %s defined multiple times", action.Name))
			actions[action.Name] = true
			continue
		}
		actions[action.Name] = false
	}

	// Validate the dispatch payload block if there
	if t.DispatchPayload != nil {
		if err := t.DispatchPayload.Validate(); err != nil {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("Dispatch Payload validation failed: %v", err))
		}
	}

View on GitHub (pinned to 482b49bf1a)