{"record":{"id":"f35139875ec21928","repo":"hashicorp/nomad","slug":"volumeid-is-required","errorCode":null,"errorMessage":"VolumeID is required","messagePattern":"VolumeID is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/structs/csi.go","lineNumber":484,"sourceCode":"\tExternalID      string // External ID of the volume to be expanded (required)\n\n\t// Capacity range (required) to be sent to the node plugin\n\tCapacity *csi.CapacityRange\n\n\t// Claim currently held for the allocation (required)\n\t// used to determine capabilities and the mount point on the client\n\tClaim *structs.CSIVolumeClaim\n}\n\nfunc (req *ClientCSINodeExpandVolumeRequest) Validate() error {\n\tvar err error\n\t// These should not occur during normal operations; they're here\n\t// mainly to catch potential programmer error.\n\tif req.PluginID == \"\" {\n\t\terr = errors.Join(err, errors.New(\"PluginID is required\"))\n\t}\n\tif req.VolumeID == \"\" {\n\t\terr = errors.Join(err, errors.New(\"VolumeID is required\"))\n\t}\n\tif req.ExternalID == \"\" {\n\t\terr = errors.Join(err, errors.New(\"ExternalID is required\"))\n\t}\n\tif req.Claim == nil {\n\t\terr = errors.Join(err, errors.New(\"Claim is required\"))\n\t} else if req.Claim.AllocationID == \"\" {\n\t\terr = errors.Join(err, errors.New(\"Claim.AllocationID is required\"))\n\t}\n\treturn err\n}\n\ntype ClientCSINodeExpandVolumeResponse struct {\n\tCapacityBytes int64\n}\n","sourceCodeStart":466,"sourceCodeEnd":500,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/structs/csi.go#L466-L500","documentation":"err(\"VolumeID is required\") is produced by ClientCSINodeExpandVolumeRequest.Validate when the VolumeID field is empty. Like its sibling checks it is a programmer-error guard; a node expand request must identify the volume being expanded. It is combined with other validation errors via errors.Join.","triggerScenarios":"Submitting a ClientCSINodeExpandVolumeRequest with VolumeID == \"\" — the volume claim lookup returned nothing or the caller passed an empty volume ID.","commonSituations":"Volume state lost on the client, claim lookups returning empty IDs, or request construction bugs after volume GC.","solutions":["Set VolumeID from the CSI volume claim before invoking the expand RPC","Confirm the volume still exists locally (not GC'd) and its ID resolves","Add a pre-call check that req.VolumeID != \"\"","Inspect the joined Validate error to catch all missing fields at once"],"exampleFix":"// before\nreq := &cstructs.ClientCSINodeExpandVolumeRequest{PluginID: pluginID}\n// after\nreq := &cstructs.ClientCSINodeExpandVolumeRequest{PluginID: pluginID, VolumeID: vol.ID, ExternalID: vol.RemoteID()}","handlingStrategy":"validation","validationCode":"if err := req.Validate(); err != nil { return err }\nif req.VolumeID == \"\" { return errors.New(\"VolumeID must be set before node expand\") }","typeGuard":null,"tryCatchPattern":"if err := req.Validate(); err != nil {\n    if strings.Contains(err.Error(), \"VolumeID is required\") {\n        // re-fetch the volume claim; it may have been GC'd\n        return refetchClaimAndRetry()\n    }\n    return err\n}","preventionTips":["Set VolumeID from the local volume claim before the RPC","Check the volume still exists (not GC'd) before expanding","Run Validate() before issuing the gRPC call","Cover request construction with tests asserting non-empty IDs"],"tags":["go","csi","validation"],"backgroundTag":"schema-validation-failed","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"}