docker/cli · error

key doesn't exist in node's labels

Error message

key %s doesn't exist in node's labels

What it means

Returned by mergeNodeUpdate (node/update.go:113) when --label-rm references a key that is absent from the node's current Spec.Annotations.Labels. The CLI deliberately fails the command rather than silently no-oping, so operators know exactly which key was not found.

Solutions

  1. Inspect the node first (`docker node inspect NODE`) and copy the exact label key.
  2. Correct typos or casing in the --label-rm argument.
  3. If the label genuinely should be gone, treat its absence as success and drop the flag from your script.

Example fix

// before
docker node update --label-rm gpu NODE   // actual label is GPU
// after
docker node update --label-rm GPU NODE
Defensive patterns

Strategy: validation

Validate before calling

// Inspect the node and confirm each removal key exists before calling update.
func nodeHasLabels(ctx context.Context, c client.NodeAPIClient, nodeID string, keys []string) error {
    res, err := c.NodeInspectWithRaw(ctx, nodeID)
    if err != nil { return err }
    labels := res.Node.Spec.Annotations.Labels
    for _, k := range keys {
        if _, ok := labels[k]; !ok {
            return fmt.Errorf("key %s doesn't exist in node's labels", k)
        }
    }
    return nil
}

Prevention

When it happens

Trigger: Running `docker node update --label-rm <key> NODE` where <key> was never set on NODE, or was already removed in a prior update. The check is a literal map lookup at update.go:112.

Common situations: Typo in the label key, case mismatch (labels are case-sensitive), attempting to remove a label that was set via the API with a different name, or scripting a cleanup that assumes labels exist.

Related errors


AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07). Data as JSON: /api/errors/f69839128ddc3395. Report an issue: GitHub.

Appendix: source

Thrown at cli/command/node/update.go:113

			str, err := flags.GetString(flagAvailability)
			if err != nil {
				return err
			}
			spec.Availability = swarm.NodeAvailability(str)
		}
		if spec.Annotations.Labels == nil {
			spec.Annotations.Labels = make(map[string]string)
		}
		if flags.Changed(flagLabelAdd) {
			labels := flags.Lookup(flagLabelAdd).Value.(*opts.ListOpts).GetSlice()
			maps.Copy(spec.Annotations.Labels, opts.ConvertKVStringsToMap(labels))
		}
		if flags.Changed(flagLabelRemove) {
			keys := flags.Lookup(flagLabelRemove).Value.(*opts.ListOpts).GetSlice()
			for _, k := range keys {
				// if a key doesn't exist, fail the command explicitly
				if _, exists := spec.Annotations.Labels[k]; !exists {
					return fmt.Errorf("key %s doesn't exist in node's labels", k)
				}
				delete(spec.Annotations.Labels, k)
			}
		}
		return nil
	}
}

const (
	flagRole         = "role"
	flagAvailability = "availability"
	flagLabelAdd     = "label-add"
	flagLabelRemove  = "label-rm"
)

View on GitHub (pinned to 4f84911bfe)