hashicorp/nomad · error

controller create volume: %v

Error message

controller create volume: %v

What it means

ClientCSI.ControllerCreateVolume forwards a CSI ControllerCreateVolume RPC to the controller plugin and wraps failures as "controller create volume: <err>". It is invoked when Nomad registers a volume with no external ID and asks the controller to provision it.

Source

Thrown at nomad/client_csi_endpoint.go:84

		"ClientCSI.ControllerDetachVolume",
		structs.RateMetricWrite,
		args, reply)
	if err != nil {
		return fmt.Errorf("controller detach volume: %v", err)
	}
	return nil
}

func (a *ClientCSI) ControllerCreateVolume(args *cstructs.ClientCSIControllerCreateVolumeRequest, reply *cstructs.ClientCSIControllerCreateVolumeResponse) error {
	defer metrics.MeasureSince([]string{"nomad", "client_csi_controller", "create_volume"}, time.Now())

	err := a.sendCSIControllerRPC(args.PluginID,
		"CSI.ControllerCreateVolume",
		"ClientCSI.ControllerCreateVolume",
		structs.RateMetricWrite,
		args, reply)
	if err != nil {
		return fmt.Errorf("controller create volume: %v", err)
	}
	return nil
}

func (a *ClientCSI) ControllerExpandVolume(args *cstructs.ClientCSIControllerExpandVolumeRequest, reply *cstructs.ClientCSIControllerExpandVolumeResponse) error {
	defer metrics.MeasureSince([]string{"nomad", "client_csi_controller", "expand_volume"}, time.Now())

	err := a.sendCSIControllerRPC(args.PluginID,
		"CSI.ControllerExpandVolume",
		"ClientCSI.ControllerExpandVolume",
		structs.RateMetricWrite,
		args, reply)
	if err != nil {
		return fmt.Errorf("controller expand volume: %v", err)
	}
	return nil
}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Check `nomad plugin status <plugin-id>` for a healthy controller; restart the plugin task if down.
  2. Inspect plugin alloc logs for the backend CSI error (quota, invalid param, capacity) and fix the storage side or the volume's parameters/topologies in the HCL.
  3. Verify the plugin advertises ControllerCreateVolume; if not, pre-provision the volume externally and register it with a volume ID instead of dynamic creation.

Example fix

# before
volume "db" {
  plugin_id   = "ebs-plugin"
  capacity_min = "10GiB"
  capacity_max = "10GiB"
  topology_request { required = true
    topology { segments = { "topology.ebs.amazonaws.com/zone" = "us-east-1f" } } }
}
# after: capacity raised / zone fixed to one the backend supports
volume "db" {
  plugin_id   = "ebs-plugin"
  capacity_min = "20GiB"
  capacity_max = "40GiB"
  topology_request { required = true
    topology { segments = { "topology.ebs.amazonaws.com/zone" = "us-east-1a" } } }
}
Defensive patterns

Strategy: try-catch

Validate before calling

const plugin = await nomad.plugin(pluginID)
const caps = plugin.controllerCapabilities ?? []
if (!caps.includes('CREATE_DELETE_VOLUME')) {
  throw new Error('plugin cannot create volumes; pre-provision and register an existing volume ID instead')
}
// verify backend has capacity/quota via plugin logs or external API

Type guard

const supportsCreate = (p) => (p.controllerCapabilities ?? []).includes('CREATE_DELETE_VOLUME')

Try / catch

try { return await createVolume(spec) }
catch (e) {
  if (String(e).startsWith('controller create volume')) {
    log.error('dynamic provisioning failed:', e)
    return provisionExternallyAndRegister(spec) // fallback path
  }
  throw e
}

Prevention

When it happens

Trigger: `nomad volume create` (dynamic provisioning) when the controller plugin is down, or the storage backend rejects creation (invalid parameters, capacity exceeded, quota, bad topology).

Common situations: External storage quota/capacity exhausted; invalid requested_capabilities or parameters block in the volume spec; plugin doesn't implement CREATE/DELETE controller capability; topology/zone mismatch (requested zone the backend can't serve).

Related errors


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