hashicorp/nomad · error

capacity_max (%d) cannot be less than existing provisioned c

Error message

capacity_max (%d) cannot be less than existing provisioned capacity (%d)

What it means

ValidateUpdate rejects shrinking a host volume's capacity_max below the capacity already provisioned on the node. If RequestedCapacityMaxBytes is positive and lower than existing.CapacityBytes, storage would be over-committed, so the update fails.

Source

Thrown at nomad/structs/host_volumes.go:198

	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.
func (hv *HostVolume) CanonicalizeForCreate(existing *HostVolume, now time.Time) {
	if existing == nil {
		hv.ID = uuid.Generate()
		if hv.PluginID == "" {
			hv.PluginID = DefaultHostVolumePlugin
		}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Raise RequestedCapacityMaxBytes to at least existing.CapacityBytes
  2. Set RequestedCapacityMaxBytes to 0 (unset) to leave the cap unchanged
  3. Rescale the actual storage on the node/CSI provider first, then update the volume

Example fix

// before
RequestedCapacityMaxBytes: 5 * 1024 * 1024 * 1024 // 5GiB < provisioned
// after
RequestedCapacityMaxBytes: 20 * 1024 * 1024 * 1024 // >= existing capacity
Defensive patterns

Strategy: validation

Validate before calling

if hv.RequestedCapacityMaxBytes > 0 && hv.RequestedCapacityMaxBytes < existing.CapacityBytes {
  return fmt.Errorf("capacity_max %d below provisioned %d", hv.RequestedCapacityMaxBytes, existing.CapacityBytes)
}

Try / catch

if err := updateVolume(hv); err != nil {
  if strings.Contains(err.Error(), "cannot be less than existing provisioned capacity") {
    hv.RequestedCapacityMaxBytes = existing.CapacityBytes
  }
}

Prevention

When it happens

Trigger: Updating a host volume with RequestedCapacityMaxBytes > 0 that is smaller than the node's current CapacityBytes for that volume (via the volume update path / validateVolumeUpdate).

Common situations: Operator tries to cap usage below what the CSI/Node reports as already provisioned; typo in byte count (e.g. GiB vs MiB); node resized independently of Nomad.

Related errors


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