{"record":{"id":"84912707617ba7d4","repo":"dgraph-io/dgraph","slug":"reuse-raftid-healthy-connection-to-a-member-with","errorCode":null,"errorMessage":"REUSE_RAFTID: Healthy connection to a member with same ID: %+v","messagePattern":"REUSE_RAFTID: Healthy connection to a member with same ID: %\\+v","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"dgraph/cmd/zero/zero.go","lineNumber":576,"sourceCode":"\t\t\tcase member.Addr == m.Addr && m.Id == 0:\n\t\t\t\tglog.Infof(\"Found a member with the same address. Returning: %+v\", member)\n\t\t\t\tconn.GetPools().Connect(m.Addr, s.tlsClientConfig)\n\t\t\t\treturn &pb.ConnectionState{\n\t\t\t\t\tState:  ms,\n\t\t\t\t\tMember: member,\n\t\t\t\t}, nil\n\n\t\t\tcase member.Addr == m.Addr && member.Id != m.Id:\n\t\t\t\t// Same address. Different Id. If Id is zero, then it might be trying to connect for\n\t\t\t\t// the first time. We can just directly return the membership information.\n\t\t\t\treturn nil, errors.Errorf(\"REUSE_ADDR: Duplicate address to existing member: %+v.\"+\n\t\t\t\t\t\" Self: +%v\", member, m)\n\n\t\t\tcase member.Addr != m.Addr && member.Id == m.Id:\n\t\t\t\t// Same Id. Different address.\n\t\t\t\tif pl, err := conn.GetPools().Get(member.Addr); err == nil && pl.IsHealthy() {\n\t\t\t\t\t// Found a healthy connection.\n\t\t\t\t\treturn nil, errors.Errorf(\"REUSE_RAFTID: Healthy connection to a member\"+\n\t\t\t\t\t\t\" with same ID: %+v\", member)\n\t\t\t\t}\n\t\t\t}\n\t\t\tnumberOfNodes++\n\t\t}\n\t}\n\n\t// Create a connection and check validity of the address by doing an Echo.\n\tconn.GetPools().Connect(m.Addr, s.tlsClientConfig)\n\n\tcreateProposal := func() *pb.ZeroProposal {\n\t\ts.Lock()\n\t\tdefer s.Unlock()\n\n\t\tproposal := new(pb.ZeroProposal)\n\t\t// Check if we already have this member.\n\t\tfor _, group := range s.state.Groups {\n\t\t\tif _, has := group.Members[m.Id]; has {","sourceCodeStart":558,"sourceCodeEnd":594,"githubUrl":"https://github.com/dgraph-io/dgraph/blob/759e242be62c91f8d084da06ad0c8d21256d9c07/dgraph/cmd/zero/zero.go#L558-L594","documentation":"During Connect, Zero found an existing member with the same Raft ID as the requester but a different address, and that old member's address still has a healthy gRPC connection. Zero concludes the ID genuinely belongs to a live node elsewhere, so a new connection with the same ID is rejected to protect Raft uniqueness. (Message assembled across two Go string literals.)","triggerScenarios":"Connect with m.Id equal to a current member's Id while m.Addr differs, and conn.GetPools().Get(member.Addr) succeeds and pl.IsHealthy() is true — i.e., two hosts simultaneously claiming the same Raft ID.","commonSituations":"Cloned VM/container images with copied raft state; a node moved to a new address without removing its old membership; a stale/recovering node reconnecting while its replacement is already healthy; misconfigured static raft IDs in fleet provisioning.","solutions":["Identify which instance truly owns the Raft ID and shut down or wipe the impostor's raft (p) state so it gets a fresh ID.","If the node legitimately moved addresses, first remove the old member (RemoveNode) or let Zero expire it, then reconnect.","Stop assigning static/duplicated --raft \"id\" values; let nodes auto-assign IDs with clean state.","Check Zero /state to see the conflicting member and its address, then fix the deployment accordingly."],"exampleFix":"// before: cloned image carries id=2 while original a1 (id=2) is still healthy\n// after on the clone:\nrm -rf p && dgraph alpha --my=a2:7080 --zero=z1:5080","handlingStrategy":"validation","validationCode":"state := fetchZeroState(\"http://zero:6080/state\")\nfor _, groups := range state.Groups {\n    for id, m := range groups.Members {\n        if id == myRaftID && m.Addr != myAddr {\n            return fmt.Errorf(\"raft id %d is live at %s; wipe local raft state or pick new id\", id, m.Addr)\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"_, err := zc.Connect(ctx, m)\nif err != nil && strings.Contains(err.Error(), \"REUSE_RAFTID\") && strings.Contains(err.Error(), \"Healthy connection\") {\n    return fmt.Errorf(\"another live member already owns raft id %d; shut down the impostor: %w\", m.Id, err)\n}","preventionTips":["Verify no other live host runs the same raft id before joining (check /state).","Avoid VM/image cloning with preserved raft state; scrub p/ in golden images.","When moving a node to a new address, remove its old membership first."],"tags":["dgraph-zero","raft","membership","duplicate-id"],"backgroundTag":"raft-id-reuse","analyzedSha":"759e242be62c91f8d084da06ad0c8d21256d9c07","analyzedAt":"2026-09-01T14:42:12.034Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}