hashicorp/nomad · error
invalid status for node
Error message
invalid status for node
What it means
The Node.Register handler defaults an empty node status to 'initializing', but if the client supplies a status string not in the valid set (initializing, pending, ready, down, disconnected), registration is rejected with 'invalid status for node'. This protects the state store from invalid status values.
Source
Thrown at nomad/node_endpoint.go:139
// value in state. This acts as a secondary check and can be seen as a
// refresh token, in the event the identity is expired.
if authErr != nil && !errors.Is(authErr, jwt.ErrExpired) {
return structs.ErrPermissionDenied
}
defer metrics.MeasureSince([]string{"nomad", "client", "register"}, time.Now())
// Perform validation of the base provided request.
if err := args.Validate(); err != nil {
return err
}
// Default the status if none is given
if args.Node.Status == "" {
args.Node.Status = structs.NodeStatusInit
}
if !structs.ValidNodeStatus(args.Node.Status) {
return fmt.Errorf("invalid status for node")
}
// Default to eligible for scheduling if unset
if args.Node.SchedulingEligibility == "" {
args.Node.SchedulingEligibility = structs.NodeSchedulingEligible
}
// Default the node pool if none is given.
if args.Node.NodePool == "" {
args.Node.NodePool = structs.NodePoolDefault
}
// The current time is used at a number of places in the registration
// workflow. Generating it once avoids multiple calls to time.Now() and also
// means the same time is used across all checks and sets.
timeNow := time.Now()
// Set the timestamp when the node is registeredView on GitHub (pinned to 482b49bf1a)
Solutions
- Omit Node.Status entirely and let the server default it to 'initializing'.
- Set status to a valid value: initializing, pending, ready, down, or disconnected.
- Upgrade the custom client/agent to match the server's Nomad version and its ValidNodeStatus vocabulary.
Example fix
// before
req := &api.NodeRegisterRequest{Node: &api.Node{Status: "active"}}
// after
req := &api.NodeRegisterRequest{Node: &api.Node{}} // server defaults to initializing
// or explicitly:
req.Node.Status = "ready" Defensive patterns
Strategy: validation
Validate before calling
var validNodeStatuses = map[string]bool{"initializing": true, "pending": true, "ready": true, "down": true, "disconnected": true}
if n.Status != "" && !validNodeStatuses[n.Status] {
return fmt.Errorf("invalid node status %q", n.Status)
} Type guard
func isValidNodeStatus(s string) bool {
switch s {
case "", "initializing", "pending", "ready", "down", "disconnected":
return true
}
return false
} Prevention
- Omit Node.Status and let the server default it.
- Only send statuses from the documented valid set.
- Keep client agents and API callers on the same Nomad version as servers.
- Add client-side enum validation mirroring structs.ValidNodeStatus.
When it happens
Trigger: A Nomad client or custom API caller sends NodeRegisterRequest with Node.Status set to an unrecognized string such as 'up', 'active', or a value from an older/different Nomad version.
Common situations: Hand-rolled clients or agents built against an outdated Nomad API; autoscalers/provisioning tooling injecting a wrong default status; copying node JSON between clusters with modified fields.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- missing secret ID
- namespace cannot contain template delimiters or parenthesis
- wait config is nil or empty
- CSI.ControllerAttachVolume: VolumeID is required
- CSI.ControllerAttachVolume: ClientCSINodeID is required
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/5899fe0ca6a13f16.
Report an issue: GitHub.