hashicorp/nomad · error
requested access mode %v, got %v
Error message
requested access mode %v, got %v
What it means
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.
Source
Thrown at plugins/csi/client.go:578
// expect have been validated, only that the ones that have been validated
// match. This appears to violate the CSI specification but until that's been
// resolved in upstream we have to loosen our validation requirements. The
// tradeoff is that we're more likely to have runtime errors during
// NodeStageVolume.
func compareCapabilities(expected *csipbv1.VolumeCapability, got []*csipbv1.VolumeCapability) error {
var err multierror.Error
NEXT_CAP:
for _, cap := range got {
expectedMode := expected.GetAccessMode().GetMode()
capMode := cap.GetAccessMode().GetMode()
// The plugin may not validate AccessMode, in which case we'll
// get UNKNOWN as our response
if capMode != csipbv1.VolumeCapability_AccessMode_UNKNOWN {
if expectedMode != capMode {
multierror.Append(&err,
fmt.Errorf("requested access mode %v, got %v", expectedMode, capMode))
continue NEXT_CAP
}
}
capBlock := cap.GetBlock()
capMount := cap.GetMount()
expectedBlock := expected.GetBlock()
expectedMount := expected.GetMount()
if capBlock != nil && expectedBlock == nil {
multierror.Append(&err, fmt.Errorf(
"'block-device' access type was not requested but was validated by the controller"))
continue NEXT_CAP
}
if capMount == nil {
continue NEXT_CAP
}View on GitHub (pinned to 482b49bf1a)
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
Example fix
// before (job volume stanza)
capability { access_mode = "multi-node-multi-writer" access_type = "mount" }
// after
capability { access_mode = "single-node-writer" access_type = "mount" } Defensive patterns
Strategy: validation
Validate before calling
// validate access modes against plugin capabilities before submitting
sup := map[csipbv1.VolumeCapability_AccessMode_Mode]bool{}
caps, _ := plugin.ControllerGetCapabilities(ctx, &csi.ControllerGetCapabilitiesRequest{})
// ...collect supported access modes from plugin/volume capabilities...
for _, cap := range req.VolumeCapabilities {
if !sup[cap.GetAccessMode().GetMode()] {
return fmt.Errorf("access mode %v not supported by plugin", cap.GetAccessMode().GetMode())
}
} Type guard
func accessModesMatch(expected, validated *csipbv1.VolumeCapability) bool {
cm := validated.GetAccessMode().GetMode()
return cm == csipbv1.VolumeCapability_AccessMode_UNKNOWN ||
expected.GetAccessMode().GetMode() == cm
} Try / catch
err := client.ControllerValidateCapabilities(ctx, req)
if err != nil {
if merr, ok := err.(*multierror.Error); ok {
for _, e := range merr.Errors {
if strings.Contains(e.Error(), "requested access mode") {
// fix the volume spec's access_mode and re-validate
}
}
}
return err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- missing VolumeCapabilities
- missing secret ID
- CSI.ControllerValidateVolume: VolumeID is required
- CSI.ControllerValidateVolume: PluginID is required
- CSI.ControllerAttachVolume: VolumeID is required
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/fd8aacbff1ae6e50.
Report an issue: GitHub.