k3s-io/k3s · critical

duplicate node name found, please use a unique name for this

Error message

duplicate node name found, please use a unique name for this node

What it means

While forming/joining etcd, each existing member name is stripped of its trailing '-<uuid8>' suffix; if the remainder equals this server's ServerNodeName but the full member name differs, another node already joined with the same node name. k3s deletes its own etcd name file (so a corrected name generates a fresh member) and aborts.

Source

Thrown at pkg/etcd/etcd.go:620

				cluster = append(cluster, fmt.Sprintf("%s=%s", member.Name, member.PeerURLs[0]))
			}
		}

		// Try to get the node name from the member name
		memberNodeName := member.Name
		if lastHyphen := strings.LastIndex(member.Name, "-"); lastHyphen > 1 {
			memberNodeName = member.Name[:lastHyphen]
		}

		// Make sure there's not already a member in the cluster with a duplicate node name
		if member.Name != e.name && memberNodeName == e.config.ServerNodeName {
			// make sure to remove the name file if a duplicate node name is used, so that we
			// generate a new member name when our node name is fixed.
			nameFile := nameFile(e.config)
			if err := os.Remove(nameFile); err != nil {
				logrus.Errorf("Failed to remove etcd name file %s: %v", nameFile, err)
			}
			return errors.New("duplicate node name found, please use a unique name for this node")
		}
	}

	if add {
		logrus.Infof("Adding member %s=%s to etcd cluster %v", e.name, e.peerURL(), cluster)
		if _, err = client.MemberAddAsLearner(clientCtx, []string{e.peerURL()}); err != nil {
			if errors.Is(err, context.DeadlineExceeded) {
				return ErrJoinTimeout
			}
			return err
		}
		cluster = append(cluster, fmt.Sprintf("%s=%s", e.name, e.peerURL()))
		state = "existing"
	} else if len(cluster) > 1 {
		logrus.Infof("Starting etcd to join cluster with members %v", cluster)
		state = "existing"
	} else {
		logrus.Infof("Starting etcd for new cluster")

View on GitHub (pinned to 6ba341e396)

Solutions

  1. Give every node a unique hostname or pass a unique --node-name (K3S_NODE_NAME) before restarting k3s.
  2. If the duplicate member is a dead node, remove it (etcdctl member remove / k3s etcd remove-member) and rejoin the fixed node.
  3. Restart k3s on the corrected node; the deleted name file causes a new member identity to be generated.

Example fix

# before: both hosts run
k3s server --node-name master
# after: unique names per host
k3s server --node-name master-a   # host 1
k3s server --node-name master-b   # host 2
Defensive patterns

Strategy: validation

Validate before calling

// Before join, verify no existing member shares this node name (ignoring uuid suffix):
func nodeNameFree(members []*etcdserverpb.Member, serverNodeName string) bool {
	for _, m := range members {
		name := m.Name
		if i := strings.LastIndex(name, "-"); i > 1 { name = name[:i] }
		if m.Name != ownFullName && name == serverNodeName { return false }
	}
	return true
}

Try / catch

if err := e.joinCluster(ctx); err != nil {
	if strings.Contains(err.Error(), "duplicate node name found") {
		// set unique --node-name on this host and restart; k3s already removed the stale name file
	}
}

Prevention

When it happens

Trigger: Two hosts configured with the same --node-name (or identical hostnames) joining one cluster; cloned VMs retaining hostname; explicit --node-name collisions across environments.

Common situations: Cloud images cloned without hostname changes; homogeneous bare-metal named identically by a provisioning system; explicit node-name set to a shared value like 'master'.

Related errors


AI-assisted analysis of k3s-io/k3s@6ba341e396 (2026-08-15). Data as JSON: /api/errors/cc2c2409a9ecda77. Report an issue: GitHub.