{"record":{"id":"d661e15c7e92831b","repo":"hashicorp/nomad","slug":"volume-snapshot-id-cannot-be-updated","errorCode":null,"errorMessage":"volume snapshot ID cannot be updated","messagePattern":"volume snapshot ID cannot be updated","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/csi.go","lineNumber":805,"sourceCode":"\tvar errs *multierror.Error\n\n\tif v.Name != other.Name && other.Name != \"\" {\n\t\terrs = multierror.Append(errs, errors.New(\"volume name cannot be updated\"))\n\t}\n\tif v.ExternalID != other.ExternalID && other.ExternalID != \"\" {\n\t\terrs = multierror.Append(errs, errors.New(\n\t\t\t\"volume external ID cannot be updated\"))\n\t}\n\tif v.PluginID != other.PluginID {\n\t\terrs = multierror.Append(errs, errors.New(\n\t\t\t\"volume plugin ID cannot be updated\"))\n\t}\n\tif v.CloneID != other.CloneID && other.CloneID != \"\" {\n\t\terrs = multierror.Append(errs, errors.New(\n\t\t\t\"volume clone ID cannot be updated\"))\n\t}\n\tif v.SnapshotID != other.SnapshotID && other.SnapshotID != \"\" {\n\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(","sourceCodeStart":787,"sourceCodeEnd":823,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/csi.go#L787-L823","documentation":"Produced by CSIVolume.Merge (nomad/structs/csi.go:802) when an update attempts to change the snapshot ID a CSI volume was created from. The snapshot ID is immutable after registration; Merge collects this violation (with all other immutable-field violations) into a multierror returned as 'validation: ...'. This keeps the volume's provenance stable so controller validation and external storage remain consistent.","triggerScenarios":"Submitting a volume update (VolumeUpsert merge path) where `other.SnapshotID` differs from the stored CSIVolume.SnapshotID and is non-empty.","commonSituations":"Changing the snapshot a volume references after creation to roll data back; generating specs from templates where the snapshot ID changes per run; attempting to 're-point' a volume at a newer snapshot instead of creating a new volume.","solutions":["Omit the snapshot ID from the update spec (empty SnapshotID is ignored) and update only mutable fields such as secrets or context","Create a new volume registration referencing the desired snapshot rather than mutating the existing one","Deregister the existing volume first if the intent is to replace it, then register the new volume with the new snapshot ID"],"exampleFix":"// before\nvolume \"data\" {\n  type        = \"csi\"\n  snapshot_id = \"snap-9999\" # differs from registered value\n}\n// after\nvolume \"data\" {\n  type = \"csi\"\n  # snapshot_id removed; snapshot provenance is immutable\n}","handlingStrategy":"validation","validationCode":"if other.SnapshotID != \"\" && existing.SnapshotID != other.SnapshotID {\n    return fmt.Errorf(\"snapshot ID %q differs from registered %q; create a new volume instead\", other.SnapshotID, existing.SnapshotID)\n}","typeGuard":"func snapshotIDMutable(existing, update *structs.CSIVolume) bool {\n    return update.SnapshotID == \"\" || update.SnapshotID == existing.SnapshotID\n}","tryCatchPattern":null,"preventionTips":["Omit snapshot_id from any update/deregister-then-register workflow specs","To re-point data at a new snapshot, register a new volume rather than mutating","Validate spec changes against `nomad volume status -verbose` output before submitting"],"tags":["csi","nomad","volume","immutable-field","snapshot"],"backgroundTag":"immutable-field-update-rejected","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"}