hashicorp/nomad · error

invalid capability: %v

Error message

invalid capability: %v

What it means

When the HCL spec contains `capability` blocks, decodeHostVolume calls parseHostVolumeCapabilities and wraps failures as `invalid capability: %v`. It indicates a capability block that doesn't decode into the expected access_mode/attachment_mode structure.

Source

Thrown at command/volume_create_host.go:263

	capacityMin, err := parseCapacityBytes(list.Filter("capacity_min"))
	if err != nil {
		return nil, fmt.Errorf("invalid capacity_min: %v", err)
	}
	vol.RequestedCapacityMinBytes = capacityMin
	capacityMax, err := parseCapacityBytes(list.Filter("capacity_max"))
	if err != nil {
		return nil, fmt.Errorf("invalid capacity_max: %v", err)
	}
	vol.RequestedCapacityMaxBytes = capacityMax

	if o := list.Filter("constraint"); len(o.Items) > 0 {
		if err := parseConstraints(&vol.Constraints, o); err != nil {
			return nil, fmt.Errorf("invalid constraint: %v", err)
		}
	}
	if o := list.Filter("capability"); len(o.Items) > 0 {
		if err := parseHostVolumeCapabilities(&vol.RequestedCapabilities, o); err != nil {
			return nil, fmt.Errorf("invalid capability: %v", err)
		}
	}

	return vol, nil
}

func parseHostVolumeCapabilities(result *[]*api.HostVolumeCapability, list *ast.ObjectList) error {
	for _, o := range list.Elem().Items {
		valid := []string{"access_mode", "attachment_mode"}
		if err := helper.CheckHCLKeys(o.Val, valid); err != nil {
			return err
		}

		ot, ok := o.Val.(*ast.ObjectType)
		if !ok {
			break
		}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Check the inner error after `invalid capability:` for the exact problem
  2. Provide `access_mode` and `attachment_mode` inside each capability block (e.g. `access_mode = "single-node-writer"`)
  3. Verify block nesting: capability must be a top-level block of the volume spec, not nested elsewhere
  4. Cross-check mode strings against the CSI spec vocabulary Nomad accepts

Example fix

// before
capability {
  mode = "rw"
}

// after
capability {
  access_mode = "single-node-writer"
  attachment_mode = "file-system"
}
Defensive patterns

Strategy: validation

Validate before calling

validAccessModes := map[string]bool{"single-node-reader":true,"single-node-writer":true,"multi-node-reader-only":true,"multi-node-single-writer":true,"multi-node-multi-writer":true}
validAttachModes := map[string]bool{"file-system":true,"block-device":true}
for _, c := range spec.Capability {
	if !validAccessModes[c.AccessMode] || !validAttachModes[c.AttachmentMode] {
		return fmt.Errorf("capability %#v has unknown access_mode/attachment_mode", c)
	}
}

Try / catch

if err := parseHostVolumeCapabilities(&vol.RequestedCapabilities, o); err != nil {
	return fmt.Errorf("capability blocks need valid access_mode and attachment_mode: %v", err)
}

Prevention

When it happens

Trigger: `nomad volume create` (host) with a `capability { ... }` block missing `access_mode`/`attachment_mode` or using unrecognized mode strings.

Common situations: Using CSI capability values not supported for host volumes, misspelling access_mode (e.g. 'acces_mode'), or nesting the block incorrectly so HCL decodes the wrong shape.

Related errors


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