{"record":{"id":"38fb65502e350e22","repo":"hashicorp/nomad","slug":"validation-error-v","errorCode":null,"errorMessage":"validation error: %v","messagePattern":"validation error: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/csi/client.go","lineNumber":864,"sourceCode":"\t\tcode := status.Code(err)\n\t\tswitch code {\n\t\tcase codes.NotFound:\n\t\t\terr = fmt.Errorf(\"%w: volume %q could not be found: %v\",\n\t\t\t\tstructs.ErrCSIClientRPCIgnorable, volumeID, err)\n\t\tcase codes.Internal:\n\t\t\terr = fmt.Errorf(\"node plugin returned an internal error, check the plugin allocation logs for more information: %v\", err)\n\t\t}\n\t}\n\n\treturn err\n}\n\nfunc (c *client) NodePublishVolume(ctx context.Context, req *NodePublishVolumeRequest, opts ...grpc.CallOption) error {\n\tif err := c.ensureConnected(ctx); err != nil {\n\t\treturn err\n\t}\n\tif err := req.Validate(); err != nil {\n\t\treturn fmt.Errorf(\"validation error: %v\", err)\n\t}\n\n\t// NodePublishVolume's response contains no extra data. If err == nil, we were\n\t// successful.\n\t_, err := c.nodeClient.NodePublishVolume(ctx, req.ToCSIRepresentation(), 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.AlreadyExists:\n\t\t\terr = fmt.Errorf(\n\t\t\t\t\"volume %q is already published at target path %q but with capabilities or a read_only setting incompatible with this request: %v\",\n\t\t\t\treq.ExternalID, req.TargetPath, err)\n\t\tcase codes.FailedPrecondition:\n\t\t\terr = fmt.Errorf(\"volume %q does not have MULTI_NODE volume capability: %v\",\n\t\t\t\treq.ExternalID, err)\n\t\tcase codes.Internal:","sourceCodeStart":846,"sourceCodeEnd":882,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/plugins/csi/client.go#L846-L882","documentation":"NodePublishVolume validates its *NodePublishVolumeRequest (via req.Validate()) before sending the CSI RPC, and returns 'validation error: %v' when any required field is missing — the Validate method on that struct checks for empty VolumeID/ExternalID, TargetPath, StagingTargetPath, and similar required request fields. This is a local precondition failure; the gRPC call is never made. Unlike the NodeUnstage checks, it aggregates whatever req.Validate reports.","triggerScenarios":"Calling client.NodePublishVolume with a NodePublishVolumeRequest whose required fields are empty — e.g. zero-value struct, missing VolumeID, missing TargetPath or StagingTargetPath, or CopyMode/ MountVolume fields left unset when required by Validate.","commonSituations":"Constructing NodePublishVolumeRequest by hand in tests or tooling; a Nomad bug where the hook built the request from an allocation whose volume fields were empty; API changes between Nomad versions adding new required fields that callers don't populate.","solutions":["Populate all required fields (ExternalID, TargetPath, StagingTargetPath, and required capability fields) before calling","Call req.Validate() yourself beforehand to get the precise missing-field message","Check how the task runner builds the request; trace which allocation volume field is empty","Diff your code against the current NodePublishVolumeRequest definition for newly added required fields"],"exampleFix":"// before\nreq := &csi.NodePublishVolumeRequest{}\nc.Client.NodePublishVolume(ctx, req)\n// after\nreq := &csi.NodePublishVolumeRequest{\n\tExternalID:        vol.ID,\n\tTargetPath:        targetPath,\n\tStagingTargetPath: stagingPath,\n\tCopyMode:          false,\n}\nif err := req.Validate(); err != nil {\n\treturn fmt.Errorf(\"publish request invalid: %w\", err)\n}\nc.Client.NodePublishVolume(ctx, req)","handlingStrategy":"validation","validationCode":"func validatePublishReq(req *csi.NodePublishVolumeRequest) error {\n\tif req == nil { return fmt.Errorf(\"nil request\") }\n\tif req.ExternalID == \"\" { return fmt.Errorf(\"missing ExternalID\") }\n\tif req.TargetPath == \"\" { return fmt.Errorf(\"missing TargetPath\") }\n\tif req.StagingTargetPath == \"\" { return fmt.Errorf(\"missing StagingTargetPath\") }\n\treturn nil\n}\n// call before client.NodePublishVolume; or simply call req.Validate() directly","typeGuard":"func publishReqValid(req *csi.NodePublishVolumeRequest) bool {\n\treturn req != nil && req.Validate() == nil\n}","tryCatchPattern":"err := client.NodePublishVolume(ctx, req)\nif err != nil && strings.HasPrefix(err.Error(), \"validation error:\") {\n\t// local request defect; do not retry — fix the request construction\n\tlogger.Error(\"invalid publish request\", \"error\", err)\n\treturn err\n}\nreturn err","preventionTips":["Run req.Validate() before every NodePublishVolume call to catch missing fields early","Never send a zero-value NodePublishVolumeRequest","Keep up to date with NodePublishVolumeRequest field changes across Nomad versions","Unit-test the request-building code path with allocation fixtures"],"tags":["csi","go","nomad","validation","volume-management"],"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"}