hashicorp/nomad · error
node ID %q is not in pool %q
Error message
node ID %q is not in pool %q
What it means
During host volume Create/Register, validateVolumeForState checks that the volume's explicit node pool actually contains the volume's explicit node ID. Nomad looks up the node's real pool and compares it with vol.NodePool; a mismatch means the request pins a node and a pool that disagree, which would corrupt pool governance. The server rejects the write rather than silently reassigning the pool.
Source
Thrown at nomad/host_volume_endpoint.go:471
if err != nil {
return err // should never hit, bail out
}
if node == nil {
return fmt.Errorf("node %q does not exist", vol.NodeID)
}
poolFromExistingNode = node.NodePool
}
if vol.NodePool != "" {
pool, err := snap.NodePoolByName(nil, vol.NodePool)
if err != nil {
return err // should never hit, bail out
}
if pool == nil {
return fmt.Errorf("node pool %q does not exist", vol.NodePool)
}
if poolFromExistingNode != "" && poolFromExistingNode != pool.Name {
return fmt.Errorf("node ID %q is not in pool %q", vol.NodeID, vol.NodePool)
}
}
return nil
}
func (v *HostVolume) createVolume(vol *structs.HostVolume) error {
method := "ClientHostVolume.Create"
cReq := &cstructs.ClientHostVolumeCreateRequest{
ID: vol.ID,
Name: vol.Name,
PluginID: vol.PluginID,
Namespace: vol.Namespace,
NodeID: vol.NodeID,
RequestedCapacityMinBytes: vol.RequestedCapacityMinBytes,
RequestedCapacityMaxBytes: vol.RequestedCapacityMaxBytes,
Parameters: vol.Parameters,View on GitHub (pinned to 482b49bf1a)
Solutions
- Set NodePool to the actual pool of the given node (query `nomad node status <id>` for its Node Pool), or omit NodePool entirely and let the server derive it from the node.
- If the pool is what you intended, omit NodeID and let placeHostVolume pick a node from that pool.
- Verify the node hasn't been moved to a different pool; update your automation/config to the node's current pool.
Example fix
// before
hv := &api.HostVolume{ NodeID: nodeId, NodePool: "dev" }
// after
node, _ := client.Nodes().Info(nodeId, nil)
hv := &api.HostVolume{ NodeID: nodeId, NodePool: node.NodePool } // or leave NodePool empty Defensive patterns
Strategy: validation
Validate before calling
node, _, err := client.Nodes().Info(vol.NodeID, nil)
if err != nil { return err }
if vol.NodePool != "" && node.NodePool != vol.NodePool {
return fmt.Errorf("node %s is in pool %q, not %q", vol.NodeID, node.NodePool, vol.NodePool)
} Prevention
- Never set both NodeID and NodePool; let the server derive the pool from the node.
- Fetch the node's current pool from the API instead of hardcoding it in specs.
- Re-validate templates after nodes move between pools.
When it happens
Trigger: Calling `nomad host volume create` (or register) with both NodeID and NodePool set, where the specified node belongs to a different node pool than the one supplied (e.g. node in 'prod' pool but request says NodePool='dev').
Common situations: Copy-pasting a job/volume spec and editing only the node pool field; automation that sets NodePool from stale inventory while NodeID comes from a scheduler or operator; a node recently moved to another pool while cached specs still reference the old pool.
Related errors
- Node Pools Governance is unlicensed.
- validating volume %q against state failed: %v
- volume validation failed: %w
- volume validation failed: no such namespace %q
- node pool %q does not exist
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/0da311fd8e92f30c.
Report an issue: GitHub.