{"record":{"id":"05da1c93e101822c","repo":"hashicorp/nomad","slug":"unable-to-update-volume-s","errorCode":null,"errorMessage":"unable to update volume: %s","messagePattern":"unable to update volume: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/csi_endpoint.go","lineNumber":348,"sourceCode":"\t\tplugin, err := v.pluginValidateVolume(vol)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// CSIVolume has many user-defined fields which are immutable\n\t\t// once set, and many fields that are controlled by Nomad and\n\t\t// are not user-settable. We merge onto a copy of the existing\n\t\t// volume to allow a user to submit a volume spec for `volume\n\t\t// create` and reuse it for updates in `volume register`\n\t\t// without having to manually remove the fields unused by\n\t\t// register (and similar use cases with API consumers such as\n\t\t// Terraform).\n\t\tif existingVol != nil {\n\t\t\texistingVol = existingVol.Copy()\n\n\t\t\t// reconcile mutable fields\n\t\t\tif err = v.reconcileVolume(plugin, existingVol, vol); err != nil {\n\t\t\t\treturn fmt.Errorf(\"unable to update volume: %s\", err)\n\t\t\t}\n\n\t\t\t*vol = *existingVol\n\n\t\t} else if len(vol.Topologies) == 0 {\n\t\t\t// The topologies for the volume have already been set\n\t\t\t// when it was created, so for newly register volumes\n\t\t\t// we accept the user's description of that topology\n\t\t\tif vol.RequestedTopologies != nil {\n\t\t\t\tvol.Topologies = vol.RequestedTopologies.Required\n\t\t\t}\n\t\t}\n\n\t\tif err := v.controllerValidateVolume(args, vol, plugin); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\twarn, err := v.enforceEnterprisePolicy(snap, vol, existingVol, args.GetIdentity().GetACLToken(), args.PolicyOverride)","sourceCodeStart":330,"sourceCodeEnd":366,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/csi_endpoint.go#L330-L366","documentation":"When registering a volume that already exists, Register copies the existing volume and calls reconcileVolume to merge mutable fields. If reconciliation fails (e.g. immutable fields changed like plugin ID, provider, or topology conflict), the update is aborted with this wrapped error.","triggerScenarios":"Re-registering an existing volume whose new definition conflicts on immutable/mutable reconcile rules handled by reconcileVolume, causing it to return an error.","commonSituations":"Changing plugin_id or external ID of an existing volume; editing a spec and re-running nomad volume register; infrastructure drift between spec and stored volume.","solutions":["Read the wrapped cause (%s) to see which field failed reconciliation and revert that field in the spec","Deregister and re-register the volume if a truly incompatible change is intended","Keep immutable fields (plugin_id, external ID, topology) unchanged in updated specs"],"exampleFix":"// before\nplugin_id = \"new-plugin\"   // conflicts with existing volume\n// after\nplugin_id = \"original-plugin\" // matches existing volume","handlingStrategy":"try-catch","validationCode":"// diff spec against existing volume before re-registering\nexisting, _ := client.CSIVolumes().Get(volID, nil)\n// ensure immutable fields (plugin_id, external ID) match spec","typeGuard":null,"tryCatchPattern":"if err := register(); err != nil && strings.Contains(err.Error(), \"unable to update volume\") {\n    var cause = errors.Unwrap(err) // inspect reconcile failure\n}","preventionTips":["Keep immutable volume fields stable across spec updates","Read the wrapped cause to identify the conflicting field","Deregister/recreate the volume when an incompatible change is truly needed"],"tags":["csi","validation","conflict"],"backgroundTag":"immutable-field-conflict","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"}