hashicorp/nomad · error

change_signal must be specified when using change_mode=%q

Error message

change_signal must be specified when using change_mode=%q

What it means

WorkloadIdentity.Validate requires that when ChangeMode is set to "signal", a ChangeSignal must also be provided. Nomad needs to know which signal to send the task when a new identity is rotated. Without a signal the restart-less rotation mechanism is under-specified, so validation rejects the identity.

Source

Thrown at nomad/structs/workload_id.go:478

		mErr.Errors = append(mErr.Errors, err)
	}

	for i, aud := range wi.Audience {
		if aud == "" {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("an empty string is an invalid audience (%d)", i+1))
		}
	}

	switch wi.ChangeMode {
	case "", WIChangeModeNoop, WIChangeModeRestart:
		// Treat "" as noop. Make sure signal isn't set.
		if wi.ChangeSignal != "" {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("can only use change_signal=%q with change_mode=%q",
				wi.ChangeSignal, WIChangeModeSignal))
		}
	case WIChangeModeSignal:
		if wi.ChangeSignal == "" {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("change_signal must be specified when using change_mode=%q", WIChangeModeSignal))
		}
	default:
		// Unknown change_mode
		mErr.Errors = append(mErr.Errors, fmt.Errorf("invalid change_mode: %s", wi.ChangeMode))
	}

	if wi.TTL > 0 && (wi.Name == "" || wi.Name == WorkloadIdentityDefaultName) {
		mErr.Errors = append(mErr.Errors, fmt.Errorf("ttl for default identity not yet supported"))
	}

	if wi.TTL < 0 {
		mErr.Errors = append(mErr.Errors, fmt.Errorf("ttl must be >= 0"))
	}

	if wi.Filepath != "" && !wi.File {
		mErr.Errors = append(mErr.Errors, fmt.Errorf("file parameter must be true in order to specify filepath"))
	}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Add change_signal (e.g. change_signal = "SIGHUP") to the identity block alongside change_mode = "signal".
  2. Alternatively drop the change_signal intent and use change_mode = "restart" which needs no signal.
  3. If no rotation is desired, omit change_mode entirely (defaults to restart).

Example fix

// before
identity {
  name = "aws"
  change_mode = "signal"
}
// after
identity {
  name = "aws"
  change_mode = "signal"
  change_signal = "SIGHUP"
}
Defensive patterns

Strategy: validation

Validate before calling

func validateChangeSignal(wi *structs.WorkloadIdentity) error {
  if wi.ChangeMode == structs.WIChangeModeSignal && wi.ChangeSignal == "" {
    return fmt.Errorf("change_signal is required when change_mode=%q", wi.ChangeMode)
  }
  return nil
}

Prevention

When it happens

Trigger: Submitting a job whose workload identity block has change_mode = "signal" but no change_signal field set (ChangeSignal == ""), e.g. in a job HCL/JSON spec or when constructing structs.WorkloadIdentity in Go and calling Validate().

Common situations: Hand-writing job HCL and forgetting change_signal after setting change_mode = "signal"; copying an identity block that used change_mode = "restart" and switching it to signal; SDK/Go code setting ChangeMode = WIChangeModeSignal without setting ChangeSignal.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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