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
- Give every node a unique hostname or pass a unique --node-name (K3S_NODE_NAME) before restarting k3s.
- If the duplicate member is a dead node, remove it (etcdctl member remove / k3s etcd remove-member) and rejoin the fixed node.
- 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
- Assign unique hostnames/node-names at provisioning time; assert uniqueness in your CMDB.
- For cloned VMs/templates, force a new hostname and machine-id before first k3s start.
- Avoid 'master'/'node' style generic names across multi-cluster fleets sharing etcd.
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
- this server has not yet been promoted from learner to voting
- tombstone file has been detected but --server is empty: back
- server node name not set
- no bootstrap data found in datastore - check server token va
- no bootstrap data is available to reconcile against
AI-assisted analysis of k3s-io/k3s@6ba341e396 (2026-08-15).
Data as JSON: /api/errors/cc2c2409a9ecda77.
Report an issue: GitHub.