hashicorp/nomad · error

no such plugin

Error message

no such plugin

What it means

ListExternal in the Nomad server's CSI endpoint returns this when the state store query for the requested plugin ID succeeds but returns no plugin object. It means the CSIPluginID supplied in the ListExternal RPC does not correspond to any CSI plugin registered with Nomad's state store. The check is a deliberate explicit nil-guard after the store lookup rather than surfacing the store error.

Source

Thrown at nomad/csi_endpoint.go:1554

		return err
	}

	// NOTE: this is the plugin's namespace, not the volume(s) because they
	// might not even be registered
	if !allowVolume(aclObj, args.RequestNamespace()) {
		return structs.ErrPermissionDenied
	}
	snap, err := v.srv.fsm.State().Snapshot()
	if err != nil {
		return err
	}

	plugin, err := snap.CSIPluginByID(nil, args.PluginID)
	if err != nil {
		return err
	}
	if plugin == nil {
		return fmt.Errorf("no such plugin")
	}
	if !plugin.HasControllerCapability(structs.CSIControllerSupportsListVolumes) {
		return fmt.Errorf("unimplemented for this plugin")
	}

	method := "ClientCSI.ControllerListVolumes"
	cReq := &cstructs.ClientCSIControllerListVolumesRequest{
		MaxEntries:    args.PerPage,
		StartingToken: args.NextToken,
	}
	cReq.PluginID = plugin.ID
	cResp := &cstructs.ClientCSIControllerListVolumesResponse{}

	err = v.srv.RPC(method, cReq, cResp)
	if err != nil {
		return err
	}
	if args.PerPage > 0 && args.PerPage < int32(len(cResp.Entries)) {

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. List registered CSI plugins (`nomad plugin status` or the /v1/plugins API) and use the exact ID of an existing controller plugin in the ListExternal request
  2. Re-register the missing plugin: run/redeploy the CSI controller job on a Nomad client so it registers with the expected ID
  3. Fix the plugin ID in your tooling/config if it was typo'd or renamed
  4. Check that the Nomad client running the controller plugin is up and connected (plugin deregistration follows node drain/failure)

Example fix

// before
args := &structs.CSIVolumeExternalListRequest{PluginID: "aws-ebs"}
// after
plugins, _, _ := client.Search(...). // or GET /v1/plugins?... 
// pick the actual registered ID, e.g. from `nomad plugin status`:
args := &structs.CSIVolumeExternalListRequest{PluginID: "aws-ebs-controller"}
Defensive patterns

Strategy: validation

Validate before calling

plugin, _, err := client.Plugins().Get(ctx, pluginID, nil)
if err != nil || plugin == nil {
    return fmt.Errorf("plugin %q not registered with Nomad", pluginID)
}

Type guard

func pluginRegistered(p *api.CSIPlugin) bool { return p != nil && p.ID != "" }

Try / catch

if err := listExternal(pluginID); err != nil {
    if strings.Contains(err.Error(), "no such plugin") {
        // refresh plugin registry list and retry with a valid ID
    } else { return err }
}

Prevention

When it happens

Trigger: Calling nomad's ListExternal (CSI external volume listing) with args.PluginID that is not registered in Nomad: a typo'd plugin ID, a plugin whose controller plugin registration was garbage-collected/deregistered (node left, controller job stopped), or calling the CSI external list API before any controller plugin for that ID has registered with a Nomad client.

Common situations: Operators using `nomad volume snapshot list` / external volume listing against a plugin that was recently unregistered; plugin ID mismatch between ACL policies/scripts and the actual registered plugin name (e.g. 'aws-ebs' vs the controller job's registered ID); a Nomad client that hosted the controller left the cluster so the plugin was deregistered.

Related errors


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