hashicorp/nomad · error
node pool cannot be updated
Error message
node pool cannot be updated
What it means
Like NodeID, a host volume's NodePool is immutable after creation. ValidateUpdate appends 'node pool cannot be updated' when the request supplies a non-empty NodePool that differs from existing.NodePool. This prevents volumes from silently moving between node pools while allocations reference them.
Source
Thrown at nomad/structs/host_volumes.go:192
func (hv *HostVolume) ValidateUpdate(existing *HostVolume) error {
if existing == nil {
return nil
}
var mErr *multierror.Error
if len(existing.Allocations) > 0 {
allocIDs := helper.ConvertSlice(existing.Allocations,
func(a *AllocListStub) string { return a.ID })
mErr = multierror.Append(mErr, fmt.Errorf(
"cannot update a volume in use: claimed by allocs (%s)",
strings.Join(allocIDs, ", ")))
}
if hv.NodeID != "" && hv.NodeID != existing.NodeID {
mErr = multierror.Append(mErr, errors.New("node ID cannot be updated"))
}
if hv.NodePool != "" && hv.NodePool != existing.NodePool {
mErr = multierror.Append(mErr, errors.New("node pool cannot be updated"))
}
if hv.RequestedCapacityMaxBytes > 0 &&
hv.RequestedCapacityMaxBytes < existing.CapacityBytes {
mErr = multierror.Append(mErr, fmt.Errorf(
"capacity_max (%d) cannot be less than existing provisioned capacity (%d)",
hv.RequestedCapacityMaxBytes, existing.CapacityBytes))
}
return mErr.ErrorOrNil()
}
const DefaultHostVolumePlugin = "default"
// CanonicalizeForCreate is called in the RPC handler to ensure we call client
// RPCs with correctly populated fields from the existing volume, even if the
// RPC request includes otherwise valid zero-values. This method should be
// called on request objects or a copy, never on a state store object directly.View on GitHub (pinned to 482b49bf1a)
Solutions
- Keep node_pool identical to the existing volume's value in update requests
- Omit node_pool from the update payload (empty string bypasses the check)
- Create a new volume in the target node pool and migrate workloads instead
- Adjust automation to preserve immutable fields (node_id, node_pool) on update
Example fix
// before update := existing.Copy() update.NodePool = "gpu-pool" // not allowed // after update := existing.Copy() // keep update.NodePool == existing.NodePool update.RequestedCapacityMaxBytes = 200 * 1024 * 1024 * 1024
Defensive patterns
Strategy: validation
Validate before calling
if update.NodePool != "" && update.NodePool != existing.NodePool {
return fmt.Errorf("node_pool is immutable (%s != %s)", existing.NodePool, update.NodePool)
} Prevention
- Preserve existing node_pool in update tooling
- Plan node-pool moves as create-new-volume + migrate operations
- Whitelist mutable fields in automation that updates volumes
When it happens
Trigger: Calling ValidateUpdate on a host volume where hv.NodePool is non-empty and differs from the existing volume's NodePool.
Common situations: Renaming/organizing node pools and trying to move existing volumes into the new pool; multi-cluster tooling that stamps a pool name onto update specs; policy changes reassigning volumes across pools.
Related errors
- node ID cannot be updated
- cannot register volume: node ID is required
- cannot register volume: host path is required
- cannot toggle global mode
- cannot update expiration TTL
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/1a45cbf78bd4991e.
Report an issue: GitHub.