{"record":{"id":"cc1450c728d1c4b9","repo":"hashicorp/nomad","slug":"volume-requested-capabilities-update-was-not-compa","errorCode":null,"errorMessage":"volume requested capabilities update was not compatible with existing capability in use","messagePattern":"volume requested capabilities update was not compatible with existing capability in use","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/csi.go","lineNumber":823,"sourceCode":"\t\terrs = multierror.Append(errs, errors.New(\n\t\t\t\"volume snapshot ID cannot be updated\"))\n\t}\n\n\t// must be compatible with volume_capabilities\n\tif v.AccessMode != CSIVolumeAccessModeUnknown ||\n\t\tv.AttachmentMode != CSIVolumeAttachmentModeUnknown {\n\t\tvar ok bool\n\t\tfor _, cap := range other.RequestedCapabilities {\n\t\t\tif cap.AccessMode == v.AccessMode &&\n\t\t\t\tcap.AttachmentMode == v.AttachmentMode {\n\t\t\t\tok = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif ok {\n\t\t\tv.RequestedCapabilities = other.RequestedCapabilities\n\t\t} else {\n\t\t\terrs = multierror.Append(errs, errors.New(\n\t\t\t\t\"volume requested capabilities update was not compatible with existing capability in use\"))\n\t\t}\n\t} else {\n\t\tv.RequestedCapabilities = other.RequestedCapabilities\n\t}\n\n\t// topologies are immutable, so topology request changes must be\n\t// compatible with the existing topology, if any\n\tif len(v.Topologies) > 0 {\n\t\tif !v.RequestedTopologies.Equal(other.RequestedTopologies) {\n\t\t\terrs = multierror.Append(errs, errors.New(\n\t\t\t\t\"volume topology request update was not compatible with existing topology\"))\n\t\t}\n\t}\n\n\t// MountOptions can be updated so long as the volume isn't in use\n\tif v.InUse() {\n\t\tif !v.MountOptions.Equal(other.MountOptions) {","sourceCodeStart":805,"sourceCodeEnd":841,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/csi.go#L805-L841","documentation":"Raised by CSIVolume.Merge (nomad/structs/csi.go:823) when the volume already has an AccessMode/AttachmentMode in use and the submitted RequestedCapabilities no longer include a capability matching the existing access/attachment mode pair. CSI volumes cannot change the mode a volume is currently mounted with; new requested capabilities are only accepted if at least one is compatible with the capability in use.","triggerScenarios":"Updating a volume (nomad volume update / VolumeUpsert) whose RequestedCapabilities list contains no entry with cap.AccessMode == v.AccessMode && cap.AttachmentMode == v.AttachmentMode, while the existing volume has non-unknown AccessMode or AttachmentMode.","commonSituations":"Switching a volume from single-node-writer to multi-node-reader while allocations are mounted; removing the original capability stanza from the spec and adding only new ones; changing filesystem/mount protocol capability that the in-use mount cannot support.","solutions":["Add a requested capability whose access/attachment mode pair matches the one currently in use, alongside any new capabilities","Stop all allocations using the volume so it is no longer in use, then update capabilities","Deregister and re-register the volume with the desired capabilities if a mode change is genuinely required"],"exampleFix":"// before\nrequested_capabilities {\n  access_mode     = \"multi-node-multi-writer\" # incompatible with in-use single-node-writer\n  attachment_mode = \"file-system\"\n}\n// after\nrequested_capabilities {\n  access_mode     = \"single-node-writer\" # keeps compatibility with in-use mode\n  attachment_mode = \"file-system\"\n}","handlingStrategy":"validation","validationCode":"// ensure at least one requested capability matches the in-use pair\nfunc compatibleCaps(existing, update *structs.CSIVolume) bool {\n    if existing.AccessMode == structs.CSIVolumeAccessModeUnknown &&\n        existing.AttachmentMode == structs.CSIVolumeAttachmentModeUnknown {\n        return true\n    }\n    for _, cap := range update.RequestedCapabilities {\n        if cap.AccessMode == existing.AccessMode && cap.AttachmentMode == existing.AttachmentMode {\n            return true\n        }\n    }\n    return false\n}","typeGuard":"func hasCapability(v *structs.CSIVolume, am structs.CSIVolumeAccessMode, at structs.CSIVolumeAttachmentMode) bool {\n    for _, c := range v.RequestedCapabilities {\n        if c.AccessMode == am && c.AttachmentMode == at {\n            return true\n        }\n    }\n    return false\n}","tryCatchPattern":null,"preventionTips":["Always retain the original access/attachment mode pair in requested_capabilities when adding new ones","Check `nomad volume status` for the current access/attachment mode before updating","Only change capability modes when the volume has zero allocations"],"tags":["csi","nomad","volume","capabilities","validation"],"backgroundTag":"incompatible-capability-update","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"}