{"record":{"id":"8bc922070d3adc34","repo":"hashicorp/nomad","slug":"missing-plugin-id","errorCode":null,"errorMessage":"missing plugin ID","messagePattern":"missing plugin ID","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/client_csi_endpoint.go","lineNumber":293,"sourceCode":"\n\t// Make the RPC\n\tif err := NodeRpc(state.Session, method, args, reply); err != nil {\n\t\treturn fmt.Errorf(\"%s error: %w\", method, err)\n\t}\n\treturn nil\n}\n\n// clientIDsForController returns a sorted list of client IDs where the\n// controller plugin is expected to be running.\nfunc (a *ClientCSI) clientIDsForController(pluginID string) ([]string, error) {\n\n\tsnap, err := a.srv.State().Snapshot()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif pluginID == \"\" {\n\t\treturn nil, fmt.Errorf(\"missing plugin ID\")\n\t}\n\n\tws := memdb.NewWatchSet()\n\n\t// note: plugin IDs are not scoped to region but volumes are. so any Nomad\n\t// client we get for a controller is already in the same region for the\n\t// volume.\n\tplugin, err := snap.CSIPluginByID(ws, pluginID)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error getting plugin: %s, %v\", pluginID, err)\n\t}\n\tif plugin == nil {\n\t\treturn nil, fmt.Errorf(\"plugin missing: %s\", pluginID)\n\t}\n\n\tclientIDs := []string{}\n\n\tif len(plugin.Controllers) == 0 {","sourceCodeStart":275,"sourceCodeEnd":311,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/client_csi_endpoint.go#L275-L311","documentation":"clientIDsForController requires a non-empty pluginID to look up the CSI plugin in state store; if the request's PluginID field is empty it returns 'missing plugin ID'. This guards against forwarding controller RPCs with no target plugin.","triggerScenarios":"A Controller* RPC (ListVolumes, Create/Delete/ListSnapshots, ControllerValidateCapacity, etc.) arrives with args.PluginID == \"\" — e.g. an API caller omitting plugin_id in the volume/endpoint request.","commonSituations":"Hand-built API requests or tooling that forgets the PluginID field; older clients or scripts written before plugin_id became a required field; copy-pasted request templates leaving the field blank.","solutions":["Set plugin_id in the request (e.g. pass -plugin to `nomad volume snapshots` or populate PluginID in the RPC args).","Verify the volume spec declares plugin_id and re-register it.","Upgrade the nomad CLI/tooling to a version that always sends PluginID."],"exampleFix":"// before\nreq := &api.VolumeValidationRequest{} // PluginID empty\n// after\nreq := &api.VolumeValidationRequest{PluginID: \"aws-ebs-controller\"}","handlingStrategy":"validation","validationCode":"if req.PluginID == \"\" {\n    return fmt.Errorf(\"PluginID is required for controller RPCs\")\n}\n// proceed with the RPC","typeGuard":"func hasPluginID(args cstructs.CSIControllerRequest) bool {\n    return args.GetPluginID() != \"\"\n}","tryCatchPattern":"err := csi.ControllerListVolumes(args, reply)\nif err != nil && strings.Contains(err.Error(), \"missing plugin ID\") {\n    return fmt.Errorf(\"caller bug: PluginID not set: %w\", err)\n}","preventionTips":["Always populate plugin_id in CSI controller RPC args.","Validate request structs before sending over the API.","Use recent nomad CLI versions that require -plugin where needed.","Lint volume specs for non-empty plugin_id."],"tags":["csi","nomad","validation","missing-parameter"],"backgroundTag":"missing-required-argument","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}