{"record":{"id":"87047b2d218325f9","repo":"hashicorp/nomad","slug":"volume-capability-validation-failed-v","errorCode":null,"errorMessage":"volume capability validation failed: %v","messagePattern":"volume capability validation failed: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/csi/client.go","lineNumber":412,"sourceCode":"\t}\n\n\tif resp.Message != \"\" {\n\t\t// this should only ever be set if Confirmed isn't set, but\n\t\t// it's not a validation failure.\n\t\tc.logger.Debug(resp.Message)\n\t}\n\n\t// The protobuf accessors below safely handle nil pointers.\n\t// The CSI spec says we can only assert the plugin has\n\t// confirmed the volume capabilities, not that it hasn't\n\t// confirmed them, so if the field is nil we have to assume\n\t// the volume is ok.\n\tconfirmedCaps := resp.GetConfirmed().GetVolumeCapabilities()\n\tif confirmedCaps != nil {\n\t\tfor _, requestedCap := range creq.VolumeCapabilities {\n\t\t\terr := compareCapabilities(requestedCap, confirmedCaps)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"volume capability validation failed: %v\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (c *client) ControllerCreateVolume(ctx context.Context, req *ControllerCreateVolumeRequest, opts ...grpc.CallOption) (*ControllerCreateVolumeResponse, error) {\n\tif err := c.ensureConnected(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\n\terr := req.Validate()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcreq := req.ToCSIRepresentation()\n\tresp, err := c.controllerClient.CreateVolume(ctx, creq, opts...)","sourceCodeStart":394,"sourceCodeEnd":430,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/plugins/csi/client.go#L394-L430","documentation":"After a successful ValidateVolumeCapabilities response, the CSI spec lets the plugin echo back the capabilities it confirmed. This client compares each requested capability against the confirmed set using compareCapabilities, and returns this error when any requested capability does not match what the volume actually supports. It means the volume exists but cannot provide the access mode or access type requested.","triggerScenarios":"Calling ControllerValidateCapabilities where req.Capabilities asks for something the volume cannot deliver — e.g. requesting MULTI_NODE_READER_ONLY when the volume was created SINGLE_NODE_WRITER, a mismatched filesystem type, or a plugin that sets resp.Message/confirmed capabilities that differ from the request.","commonSituations":"A Nomad volume spec declares capabilities (access_mode/attachment_mode) that the storage backend volume does not support; the volume was created with different capabilities than the task group requests; a plugin upgrade began confirming capabilities and exposed a pre-existing spec mismatch; multiple task groups request conflicting access modes on the same volume.","solutions":["Align the requested capabilities in the volume spec with what the volume supports — check the plugin's documented access modes/attachment modes and update volume_capabilities accordingly.","Re-create or resize/convert the volume on the storage backend so it supports the requested access mode, or create a new volume with matching capabilities.","Check the plugin's resp.Message and compareCapabilities output in the error text to see exactly which capability differs, then adjust that single field.","If a plugin upgrade introduced stricter confirmation, update client volume specs to match the plugin's confirmed capabilities or pin the older plugin version."],"exampleFix":"// before\nvolume {\n  type            = \"csi\"\n  attachment_mode = \"file-system\"\n  access_mode     = \"multi-node-single-writer\"  # unsupported by this plugin\n}\n\n// after\nvolume {\n  type            = \"csi\"\n  attachment_mode = \"file-system\"\n  access_mode     = \"single-node-writer\"  # matches volume's confirmed capability\n}","handlingStrategy":"validation","validationCode":"err := csi.ControllerValidateCapabilities(ctx, &csi.ControllerValidateVolumeRequest{\n    ExternalID:   volID,\n    Capabilities: wantCaps,\n})\n// compare wantCaps against plugin-advertised capabilities from\n// ControllerGetCapabilities before committing the volume to the spec","typeGuard":"func capsMatch(want, confirmed []*csi.VolumeCapability) bool {\n    for _, w := range want {\n        if compareCapabilities(w, confirmed) != nil {\n            return false\n        }\n    }\n    return true\n}","tryCatchPattern":"if err := client.ControllerValidateCapabilities(ctx, req); err != nil {\n    if strings.Contains(err.Error(), \"capability validation failed\") {\n        return fmt.Errorf(\"spec declares unsupported capabilities: %w\", err)\n    }\n    return err\n}","preventionTips":["Verify volume specs against the plugin's advertised ControllerGetCapabilities before applying them.","Keep access_mode/attachment_mode in the create spec and the task-group spec consistent.","After CSI plugin upgrades, re-run validation against existing volumes to catch newly confirmed mismatches.","Avoid sharing one volume across task groups with conflicting access modes."],"tags":["csi","validation","capability-mismatch","storage"],"backgroundTag":"capability-mismatch","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"}