hashicorp/nomad · error

one of LimitBytes or RequiredBytes must be set

Error message

one of LimitBytes or RequiredBytes must be set

What it means

This error is returned by ControllerExpandVolumeRequest.Validate when both LimitBytes and RequiredBytes are 0. A CSI expansion must state a target capacity; since per the spec a value of 0 means 'unspecified', an expand request with no capacity at all is ambiguous and rejected locally before the gRPC call.

Source

Thrown at plugins/csi/plugin.go:651

		return errors.New("missing ExternalVolumeID")
	}
	return nil
}

type ControllerExpandVolumeRequest struct {
	ExternalVolumeID string
	RequiredBytes    int64
	LimitBytes       int64
	Capability       *VolumeCapability
	Secrets          structs.CSISecrets
}

func (r *ControllerExpandVolumeRequest) Validate() error {
	if r.ExternalVolumeID == "" {
		return errors.New("missing ExternalVolumeID")
	}
	if r.LimitBytes == 0 && r.RequiredBytes == 0 {
		return errors.New("one of LimitBytes or RequiredBytes must be set")
	}
	// per the spec: "A value of 0 is equal to an unspecified field value."
	// so in this case, only error if both are set.
	if r.LimitBytes > 0 && (r.LimitBytes < r.RequiredBytes) {
		return errors.New("LimitBytes cannot be less than RequiredBytes")
	}
	return nil
}

func (r *ControllerExpandVolumeRequest) ToCSIRepresentation() *csipbv1.ControllerExpandVolumeRequest {
	if r == nil {
		return nil
	}
	return &csipbv1.ControllerExpandVolumeRequest{
		VolumeId: r.ExternalVolumeID,
		CapacityRange: &csipbv1.CapacityRange{
			RequiredBytes: r.RequiredBytes,
			LimitBytes:    r.LimitBytes,

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Set RequiredBytes (the minimum new capacity) on the expand request.
  2. Optionally also set LimitBytes >= RequiredBytes if the provider needs an acceptable range.
  3. Fix the CLI/config plumbing so the new capacity value reaches the request.
  4. Add a pre-call guard: if RequiredBytes == 0 && LimitBytes == 0, refuse to build the request.

Example fix

// before
req := &ControllerExpandVolumeRequest{ExternalVolumeID: id}
// after
req := &ControllerExpandVolumeRequest{
  ExternalVolumeID: id,
  RequiredBytes:    20 * 1024 * 1024 * 1024,
}
Defensive patterns

Strategy: validation

Validate before calling

if req.RequiredBytes == 0 && req.LimitBytes == 0 {
	return fmt.Errorf("expand requires a target capacity: set RequiredBytes")
}

Type guard

func hasCapacity(r *ControllerExpandVolumeRequest) bool {
	return r != nil && (r.RequiredBytes != 0 || r.LimitBytes != 0)
}

Prevention

When it happens

Trigger: Calling ControllerExpandVolume with {ExternalVolumeID: "vol-1"} but neither RequiredBytes nor LimitBytes set — e.g. the new size was lost during request construction or the CLI parsed no capacity argument.

Common situations: Automation submitting an expand job with an empty capacity template; a CLI flag (--capacity) omitted so 0 is passed through; code that copies only the external ID from the old request and forgets the new capacity fields.

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


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