{"record":{"id":"fd8aacbff1ae6e50","repo":"hashicorp/nomad","slug":"requested-access-mode-v-got-v","errorCode":null,"errorMessage":"requested access mode %v, got %v","messagePattern":"requested access mode (.+?), got (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/csi/client.go","lineNumber":578,"sourceCode":"// expect have been validated, only that the ones that have been validated\n// match. This appears to violate the CSI specification but until that's been\n// resolved in upstream we have to loosen our validation requirements. The\n// tradeoff is that we're more likely to have runtime errors during\n// NodeStageVolume.\nfunc compareCapabilities(expected *csipbv1.VolumeCapability, got []*csipbv1.VolumeCapability) error {\n\tvar err multierror.Error\nNEXT_CAP:\n\tfor _, cap := range got {\n\n\t\texpectedMode := expected.GetAccessMode().GetMode()\n\t\tcapMode := cap.GetAccessMode().GetMode()\n\n\t\t// The plugin may not validate AccessMode, in which case we'll\n\t\t// get UNKNOWN as our response\n\t\tif capMode != csipbv1.VolumeCapability_AccessMode_UNKNOWN {\n\t\t\tif expectedMode != capMode {\n\t\t\t\tmultierror.Append(&err,\n\t\t\t\t\tfmt.Errorf(\"requested access mode %v, got %v\", expectedMode, capMode))\n\t\t\t\tcontinue NEXT_CAP\n\t\t\t}\n\t\t}\n\n\t\tcapBlock := cap.GetBlock()\n\t\tcapMount := cap.GetMount()\n\t\texpectedBlock := expected.GetBlock()\n\t\texpectedMount := expected.GetMount()\n\n\t\tif capBlock != nil && expectedBlock == nil {\n\t\t\tmultierror.Append(&err, fmt.Errorf(\n\t\t\t\t\"'block-device' access type was not requested but was validated by the controller\"))\n\t\t\tcontinue NEXT_CAP\n\t\t}\n\n\t\tif capMount == nil {\n\t\t\tcontinue NEXT_CAP\n\t\t}","sourceCodeStart":560,"sourceCodeEnd":596,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/plugins/csi/client.go#L560-L596","documentation":"During ControllerValidateCapabilities, Nomad compares each requested VolumeCapability against the capabilities the controller plugin says it validated. If the plugin reports a validated access mode different from the one requested (and not UNKNOWN), Nomad records 'requested access mode %v, got %v' into the returned multierror.","triggerScenarios":"Calling ControllerValidateCapabilities with a VolumeCapability whose AccessMode (e.g. MULTI_NODE_READER_ONLY) differs from the access mode the plugin validated and echoed back (e.g. SINGLE_NODE_WRITER), for capabilities other than the single-node-writer exception path.","commonSituations":"Job volume stanza declares access_mode = \"multi-node-multi-writer\" but the storage driver only supports single-node-writer; a plugin version change altered which access mode it reports validating; copying a volume block from another job with a different access mode; typo in HCL access_mode value.","solutions":["Align the job's volume capability access_mode with what the plugin actually supports (check the driver docs / ControllerGetCapabilities)","Inspect the full multierror output to see which capability mismatched and update the volume specification","Downgrade to an access mode the plugin validates, e.g. single-node-writer for RWO filesystems","Re-run ControllerValidateCapabilities after fixing to confirm all capabilities pass"],"exampleFix":"// before (job volume stanza)\ncapability { access_mode = \"multi-node-multi-writer\"  access_type = \"mount\" }\n// after\ncapability { access_mode = \"single-node-writer\"  access_type = \"mount\" }","handlingStrategy":"validation","validationCode":"// validate access modes against plugin capabilities before submitting\nsup := map[csipbv1.VolumeCapability_AccessMode_Mode]bool{}\ncaps, _ := plugin.ControllerGetCapabilities(ctx, &csi.ControllerGetCapabilitiesRequest{})\n// ...collect supported access modes from plugin/volume capabilities...\nfor _, cap := range req.VolumeCapabilities {\n    if !sup[cap.GetAccessMode().GetMode()] {\n        return fmt.Errorf(\"access mode %v not supported by plugin\", cap.GetAccessMode().GetMode())\n    }\n}","typeGuard":"func accessModesMatch(expected, validated *csipbv1.VolumeCapability) bool {\n    cm := validated.GetAccessMode().GetMode()\n    return cm == csipbv1.VolumeCapability_AccessMode_UNKNOWN ||\n        expected.GetAccessMode().GetMode() == cm\n}","tryCatchPattern":"err := client.ControllerValidateCapabilities(ctx, req)\nif err != nil {\n    if merr, ok := err.(*multierror.Error); ok {\n        for _, e := range merr.Errors {\n            if strings.Contains(e.Error(), \"requested access mode\") {\n                // fix the volume spec's access_mode and re-validate\n            }\n        }\n    }\n    return err\n}","preventionTips":["Cross-check the job's access_mode against the storage driver's documented supported modes","Never copy volume capability stanzas between jobs with different access requirements","Pin and test plugin versions; re-run validation after plugin upgrades","Use single-node-writer unless the driver explicitly supports multi-writer"],"tags":["csi","access-mode","validation","volume-capability"],"backgroundTag":"csi-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"}