{"record":{"id":"df78a64686a50996","repo":"hashicorp/nomad","slug":"volume-identity-cannot-be-updated-s","errorCode":null,"errorMessage":"volume identity cannot be updated: %s","messagePattern":"volume identity cannot be updated: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/state/state_store.go","lineNumber":2670,"sourceCode":"\tfor _, v := range volumes {\n\t\tif exists, err := s.namespaceExists(txn, v.Namespace); err != nil {\n\t\t\treturn err\n\t\t} else if !exists {\n\t\t\treturn fmt.Errorf(\"volume %s is in nonexistent namespace %s\", v.ID, v.Namespace)\n\t\t}\n\n\t\tobj, err := txn.First(TableCSIVolumes, \"id\", v.Namespace, v.ID)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"volume existence check error: %v\", err)\n\t\t}\n\t\tif obj != nil {\n\t\t\t// Allow some properties of a volume to be updated in place, but\n\t\t\t// prevent accidentally overwriting important properties.\n\t\t\told := obj.(*structs.CSIVolume)\n\t\t\tif old.ExternalID != v.ExternalID ||\n\t\t\t\told.PluginID != v.PluginID ||\n\t\t\t\told.Provider != v.Provider {\n\t\t\t\treturn fmt.Errorf(\"volume identity cannot be updated: %s\", v.ID)\n\t\t\t}\n\t\t} else {\n\t\t\tv.CreateIndex = index\n\t\t}\n\t\tv.ModifyIndex = index\n\n\t\t// Allocations are copy on write, so we want to keep the Allocation ID\n\t\t// but we need to clear the pointer so that we don't store it when we\n\t\t// write the volume to the state store. We'll get it from the db in\n\t\t// denormalize.\n\t\tfor allocID := range v.ReadAllocs {\n\t\t\tv.ReadAllocs[allocID] = nil\n\t\t}\n\t\tfor allocID := range v.WriteAllocs {\n\t\t\tv.WriteAllocs[allocID] = nil\n\t\t}\n\n\t\terr = txn.Insert(TableCSIVolumes, v)","sourceCodeStart":2652,"sourceCodeEnd":2688,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/state/state_store.go#L2652-L2688","documentation":"CSI volumes have immutable identity fields: ExternalID (provider volume ID), PluginID, and Provider. If a registration attempts to update an existing volume but these identity fields differ from the stored volume, the store rejects the change with this error to prevent accidentally re-pointing a volume at a different provider volume.","triggerScenarios":"CSIVolumeRegister on an existing volume ID whose HCL changed external_id, plugin_id, or provider compared to the stored volume.","commonSituations":"Re-running volume registration after the storage backend was recreated with a new external ID; migrating volumes to a different CSI plugin; copy-pasted specs with edited identity fields.","solutions":["Keep external_id, plugin_id, and provider unchanged in the updated spec","If the provider volume truly changed, deregister (nomad volume deregister) and register a new volume under a new ID","Revert the volume HCL to the original identity values before re-registering"],"exampleFix":"// before\nid           = \"my-volume\"\nexternal_id  = \"vol-new-abc123\"\n// after: restore original identity or use a new volume ID\nid           = \"my-volume-2\"\nexternal_id  = \"vol-new-abc123\"","handlingStrategy":"validation","validationCode":"old, _, err := client.CSIVolumes().Info(vol.ID, nil)\nif err == nil && old != nil {\n  if old.ExternalID != vol.ExternalID || old.PluginID != vol.PluginID || old.Provider != vol.Provider {\n    return fmt.Errorf(\"identity fields of volume %s are immutable\", vol.ID)\n  }\n}","typeGuard":"func identityChanged(old, cur *api.CSIVolume) bool {\n  return old.ExternalID != cur.ExternalID ||\n    old.PluginID != cur.PluginID ||\n    old.Provider != cur.Provider\n}","tryCatchPattern":"_, err := client.CSIVolumes().Register(vol, nil, nil)\nif err != nil && strings.Contains(err.Error(), \"identity cannot be updated\") {\n  // fetch current volume, diff identity fields, revert or deregister+register new ID\n}","preventionTips":["Never edit external_id, plugin_id, or provider in existing volume specs","Manage volume HCL in version control to diff changes","If the provider volume changed, deregister and register a new volume ID instead"],"tags":["nomad","csi","volume","immutability"],"backgroundTag":"immutable-field-update","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}