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
- Add change_signal (e.g. change_signal = "SIGHUP") to the identity block alongside change_mode = "signal".
- Alternatively drop the change_signal intent and use change_mode = "restart" which needs no signal.
- 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
- Always pair change_mode = "signal" with a change_signal value in job templates.
- Lint job HCL for identity blocks before submission.
- Default templates should include change_signal commented next to change_mode.
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
- can only use change_signal=%q with change_mode=%q
- file parameter must be true in order to specify filepath
- wait config is nil or empty
- missing datacenter for client registration
- default_identity_ttl must be greater than 0
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/04bb3791e1157f86.
Report an issue: GitHub.