{"record":{"id":"48f7c6080c231c5d","repo":"hashicorp/nomad","slug":"missing-volume-id-48f7c6","errorCode":null,"errorMessage":"missing volume ID","messagePattern":"missing volume ID","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/csi/client.go","lineNumber":376,"sourceCode":"\t\t\t// checkpointed. we'll return an error so the caller can log it for\n\t\t\t// diagnostic purposes.\n\t\t\terr = fmt.Errorf(\"%w: volume %q or node %q could not be found: %v\",\n\t\t\t\tstructs.ErrCSIClientRPCIgnorable, req.ExternalID, req.NodeID, err)\n\t\tcase codes.Internal:\n\t\t\terr = fmt.Errorf(\"controller plugin returned an internal error, check the plugin allocation logs for more information: %v\", err)\n\t\t}\n\t\treturn nil, err\n\t}\n\n\treturn &ControllerUnpublishVolumeResponse{}, nil\n}\n\nfunc (c *client) ControllerValidateCapabilities(ctx context.Context, req *ControllerValidateVolumeRequest, opts ...grpc.CallOption) error {\n\tif err := c.ensureConnected(ctx); err != nil {\n\t\treturn err\n\t}\n\tif req.ExternalID == \"\" {\n\t\treturn fmt.Errorf(\"missing volume ID\")\n\t}\n\n\tif req.Capabilities == nil {\n\t\treturn fmt.Errorf(\"missing Capabilities\")\n\t}\n\n\tcreq := req.ToCSIRepresentation()\n\tresp, err := c.controllerClient.ValidateVolumeCapabilities(ctx, creq, opts...)\n\tif err != nil {\n\t\tcode := status.Code(err)\n\t\tswitch code {\n\t\tcase codes.NotFound:\n\t\t\terr = fmt.Errorf(\"volume %q could not be found: %v\", req.ExternalID, err)\n\t\tcase codes.Internal:\n\t\t\terr = fmt.Errorf(\"controller plugin returned an internal error, check the plugin allocation logs for more information: %v\", err)\n\t\t}\n\t\treturn err\n\t}","sourceCodeStart":358,"sourceCodeEnd":394,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/plugins/csi/client.go#L358-L394","documentation":"This error is returned by ControllerValidateCapabilities in the CSI client wrapper when the request's ExternalID field is empty. The library refuses to send a gRPC ValidateVolumeCapabilities call to the CSI controller plugin without a volume ID, because the plugin cannot identify which volume to validate and would return an unhelpful generic error. It is a fail-fast precondition check on the client side.","triggerScenarios":"Calling client.ControllerValidateCapabilities with a *ControllerValidateVolumeRequest whose ExternalID field is the empty string. Typically happens when the caller obtained the volume ID from a failed lookup, an unset variable/field, or constructed the request without populating ExternalID.","commonSituations":"Volume registration state was lost or never populated so the stored external volume ID is empty; a Nomad volume spec omitted the required external ID; automation scripting built the request struct and forgot to set ExternalID; an upstream API returned an empty ID after a failed create that the caller did not check.","solutions":["Set req.ExternalID to the CSI volume ID from the storage provider (e.g. the ID returned by ControllerCreateVolume or listed by the plugin) before calling ControllerValidateCapabilities.","Check where the volume ID was sourced from (volume registration, Nomad volume spec's external_id, provider console/API) and fix the empty source value.","Add a caller-side check that the volume ID is non-empty and log the request construction path to find where it was lost."],"exampleFix":"// before\nreq := &csi.ControllerValidateVolumeRequest{}\nerr := client.ControllerValidateCapabilities(ctx, req)\n\n// after\nif volume.ExternalID == \"\" {\n    return fmt.Errorf(\"volume %q has no external ID; re-register the volume\", volume.Name)\n}\nreq := &csi.ControllerValidateVolumeRequest{ExternalID: volume.ExternalID}\nerr := client.ControllerValidateCapabilities(ctx, req)","handlingStrategy":"validation","validationCode":"func validateVolumeReq(req *csi.ControllerValidateVolumeRequest) error {\n    if req == nil || req.ExternalID == \"\" {\n        return fmt.Errorf(\"ControllerValidateVolumeRequest.ExternalID must be set\")\n    }\n    return nil\n}","typeGuard":"func hasExternalID(req *csi.ControllerValidateVolumeRequest) bool {\n    return req != nil && strings.TrimSpace(req.ExternalID) != \"\"\n}","tryCatchPattern":null,"preventionTips":["Always derive ExternalID from a checked source (e.g. the ControllerCreateVolumeResponse) and error out at request-construction time if empty.","Validate volume registration state (nomad volume status) before issuing controller RPCs.","Add unit tests covering zero-value request structs."],"tags":["csi","validation","missing-argument","storage"],"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-08T15:18:49.778Z"}