hashicorp/nomad · error
volume plugin ID cannot be updated
Error message
volume plugin ID cannot be updated
What it means
Produced by CSIVolume.Merge (nomad/structs/csi.go): a volume's PluginID identifies which CSI plugin/controller serves it and cannot be changed after registration. Unlike the other fields, there is no empty-string exemption — any difference between the existing volume's PluginID and the incoming one appends "volume plugin ID cannot be updated" to the multierror.
Source
Thrown at nomad/structs/csi.go:797
// user-settable. Merge will return an error if we try to mutate the
// user-defined immutable fields after they're set, but silently
// ignore fields that are controlled by Nomad.
func (v *CSIVolume) Merge(other *CSIVolume) error {
if other == nil {
return nil
}
var errs *multierror.Error
if v.Name != other.Name && other.Name != "" {
errs = multierror.Append(errs, errors.New("volume name cannot be updated"))
}
if v.ExternalID != other.ExternalID && other.ExternalID != "" {
errs = multierror.Append(errs, errors.New(
"volume external ID cannot be updated"))
}
if v.PluginID != other.PluginID {
errs = multierror.Append(errs, errors.New(
"volume plugin ID cannot be updated"))
}
if v.CloneID != other.CloneID && other.CloneID != "" {
errs = multierror.Append(errs, errors.New(
"volume clone ID cannot be updated"))
}
if v.SnapshotID != other.SnapshotID && other.SnapshotID != "" {
errs = multierror.Append(errs, errors.New(
"volume snapshot ID cannot be updated"))
}
// must be compatible with volume_capabilities
if v.AccessMode != CSIVolumeAccessModeUnknown ||
v.AttachmentMode != CSIVolumeAttachmentModeUnknown {
var ok bool
for _, cap := range other.RequestedCapabilities {
if cap.AccessMode == v.AccessMode &&
cap.AttachmentMode == v.AttachmentMode {View on GitHub (pinned to 482b49bf1a)
Solutions
- Deregister the volume (nomad volume deregister <id>) and register it against the new plugin as a fresh volume.
- Keep the plugin_id in the volume spec identical to the registered one if you only intend to update claims or other mutable fields.
- Check the plugin's advertised ID (nomad plugin status) and use that exact value in your volume spec.
Example fix
// before: changing plugin under the same volume id id = "ebs-0" plugin_id = "ebs.csi.aws.com-v2" // was "ebs.csi.aws.com" // after // nomad volume deregister ebs-0 id = "ebs-0" plugin_id = "ebs.csi.aws.com-v2" // registered fresh
Defensive patterns
Strategy: validation
Validate before calling
existing, _ := client.Volumes().Get(ctx, volID)
if existing != nil && spec.PluginID != existing.PluginID {
return fmt.Errorf("volume %s: plugin_id is immutable; deregister and register under the new plugin", volID)
} Try / catch
if err := csiVolume.Merge(update); err != nil {
if strings.Contains(err.Error(), "volume plugin ID cannot be updated") {
return fmt.Errorf("plugin cannot change for an existing volume: re-register it")
}
return err
} Prevention
- Pin plugin_id in volume specs to the plugin's advertised ID (`nomad plugin status`).
- During plugin migrations, deregister volumes before changing plugin_id.
- Note PluginID is checked unconditionally — even an empty incoming plugin_id that differs fails.
When it happens
Trigger: Updating/reconciling a CSI volume whose spec specifies a different plugin_id (e.g. moving from one storage plugin to another, or after a plugin rename/upgrade changing its ID) while keeping the same Nomad volume ID.
Common situations: Migrating between CSI plugin versions or vendors; plugin ID changed after a plugin upgrade; registering the same volume ID against the wrong plugin deployment.
Related errors
- volume name cannot be updated
- volume external ID cannot be updated
- CSI.ControllerAttachVolume: VolumeID is required
- CSI.ControllerAttachVolume: ClientCSINodeID is required
- CSI.ControllerDetachVolume: VolumeID is required
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/177bfd4d1100a91e.
Report an issue: GitHub.