hashicorp/nomad · error

CSIPluginConfig must have a non-empty PluginID

Error message

CSIPluginConfig must have a non-empty PluginID

What it means

During Task.Validate in nomad/structs/structs.go, if a task declares a csi_plugin block, the CSIPluginConfig.ID (PluginID) must be non-empty. Nomad cannot route volume/plugin operations without knowing which CSI plugin the task deploys or uses. The check is a plain empty-string test on CSIPluginConfig.ID.

Source

Thrown at nomad/structs/structs.go:8409

			mErr.Errors = append(mErr.Errors, serviceErr)
		}
	}

	// Validation for volumes
	for idx, vm := range t.VolumeMounts {
		if _, ok := tg.Volumes[vm.Volume]; !ok {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("Volume Mount (%d) references undefined volume %s", idx, vm.Volume))
		}

		if err := vm.Validate(); err != nil {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("Volume Mount (%d) is invalid: \"%w\"", idx, err))
		}
	}

	// Validate CSI Plugin Config
	if t.CSIPluginConfig != nil {
		if t.CSIPluginConfig.ID == "" {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("CSIPluginConfig must have a non-empty PluginID"))
		}

		if !CSIPluginTypeIsValid(t.CSIPluginConfig.Type) {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("CSIPluginConfig PluginType must be one of 'node', 'controller', or 'monolith', got: \"%s\"", t.CSIPluginConfig.Type))
		}

		if t.CSIPluginConfig.StagePublishBaseDir != "" && t.CSIPluginConfig.MountDir != "" &&
			helper.IsSubdirectory(t.CSIPluginConfig.MountDir, t.CSIPluginConfig.StagePublishBaseDir) {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("CSIPluginConfig StagePublishBaseDir must not be a subdirectory of MountDir, got: StagePublishBaseDir=\"%s\" MountDir=\"%s\"", t.CSIPluginConfig.StagePublishBaseDir, t.CSIPluginConfig.MountDir))
		}

		// TODO: Investigate validation of the PluginMountDir. Not much we can do apart from check IsAbs until after we understand its execution environment though :(
	}

	// Validate default Identity
	if t.Identity != nil {
		if err := t.Identity.Validate(); err != nil {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("Identity %q is invalid: %w", t.Identity.Name, err))

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Set the id field inside the task's csi_plugin block to the plugin's CSIPluginName (the plugin_id of the registered CSI plugin)
  2. Verify with `nomad plugin status` which plugin ID to use and copy it exactly
  3. If the task is not meant to deploy a CSI plugin, remove the csi_plugin block entirely

Example fix

// before
csi_plugin {
  type = "node"
}
// after
csi_plugin {
  id   = "aws-efs0"
  type = "node"
}
Defensive patterns

Strategy: validation

Validate before calling

if t.CSIPluginConfig != nil && t.CSIPluginConfig.ID == "" {
    return errors.New("csi_plugin requires a non-empty id (plugin ID)")
}

Type guard

func hasPluginID(cfg *structs.CSIPluginConfig) bool { return cfg != nil && strings.TrimSpace(cfg.ID) != "" }

Prevention

When it happens

Trigger: Submitting a job whose task has a csi_plugin { } block that omits the id field, or sets id = ""; programmatic construction of a Task with CSIPluginConfig non-nil but ID unset (e.g. via jobspec parsing or the Go API).

Common situations: HCL jobspec missing the id argument inside csi_plugin; templating a job where the plugin id variable renders empty; API clients building Task structs that set CSIPluginConfig.Type but forget ID.

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/dc171b960ae843cd. Report an issue: GitHub.