hashicorp/nomad · error

one of LimitBytes or RequiredBytes must be set if…

Error message

one of LimitBytes or RequiredBytes must be set if CapacityRange is set

What it means

ControllerCreateVolumeRequest.Validate() rejects a CapacityRange where both LimitBytes and RequiredBytes are zero. If you declare a capacity range at all, it must contain at least one meaningful bound; an all-zero range conveys no constraint and is treated as a caller bug.

Solutions

  1. Set at least one of RequiredBytes or LimitBytes to a positive byte value in the CapacityRange
  2. If no capacity constraint is intended, leave CapacityRange nil instead of passing an empty struct
  3. Check the config-to-bytes conversion for the volume size setting

Example fix

// before
req := &csi.ControllerCreateVolumeRequest{
    Name:               "vol-1",
    VolumeCapabilities: caps,
    CapacityRange:      &csi.CapacityRange{}, // both zero -> error
}
// after
req := &csi.ControllerCreateVolumeRequest{
    Name:               "vol-1",
    VolumeCapabilities: caps,
    CapacityRange:      &csi.CapacityRange{RequiredBytes: 10 * 1024 * 1024 * 1024},
}
Defensive patterns

Strategy: validation

Validate before calling

func validateCapacity(req *csi.ControllerCreateVolumeRequest) error {
    cr := req.CapacityRange
    if cr != nil && cr.LimitBytes == 0 && cr.RequiredBytes == 0 {
        return errors.New("CapacityRange set but both LimitBytes and RequiredBytes are zero")
    }
    return nil
}

Type guard

func hasUsableCapacity(req *csi.ControllerCreateVolumeRequest) bool {
    cr := req.CapacityRange
    return cr == nil || cr.LimitBytes > 0 || cr.RequiredBytes > 0
}

Try / catch

if err := req.Validate(); err != nil {
    if strings.Contains(err.Error(), "LimitBytes or RequiredBytes") {
        return fmt.Errorf("create refused: set a positive byte value or omit CapacityRange entirely: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Setting CapacityRange to &csi.CapacityRange{} (or a struct populated from config where both size fields rendered as 0) and then calling ControllerCreateVolume.

Common situations: Config parsing that failed to convert a human size (e.g. "10Gi") into bytes, silently yielding zeros; template typos like required_bytes vs requiredBytes; callers copying the CapacityRange pointer without its values.

Related errors


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

Appendix: source

Thrown at plugins/csi/plugin.go:501

		Parameters:                r.Parameters,
		Secrets:                   r.Secrets,
		VolumeContentSource:       r.ContentSource.ToCSIRepresentation(),
		AccessibilityRequirements: r.AccessibilityRequirements.ToCSIRepresentation(),
	}

	return req
}

func (r *ControllerCreateVolumeRequest) Validate() error {
	if r.Name == "" {
		return errors.New("missing Name")
	}
	if r.VolumeCapabilities == nil {
		return errors.New("missing VolumeCapabilities")
	}
	if r.CapacityRange != nil {
		if r.CapacityRange.LimitBytes == 0 && r.CapacityRange.RequiredBytes == 0 {
			return errors.New(
				"one of LimitBytes or RequiredBytes must be set if CapacityRange is set")
		}
		if r.CapacityRange.LimitBytes > 0 &&
			r.CapacityRange.LimitBytes < r.CapacityRange.RequiredBytes {
			return errors.New("LimitBytes cannot be less than RequiredBytes")
		}
	}
	if r.ContentSource != nil {
		if r.ContentSource.CloneID != "" && r.ContentSource.SnapshotID != "" {
			return errors.New(
				"one of SnapshotID or CloneID must be set if ContentSource is set")
		}
	}
	return nil
}

// VolumeContentSource is snapshot or volume that the plugin will use to
// create the new volume. At most one of these fields can be set, but nil (and

View on GitHub (pinned to 482b49bf1a)