{"record":{"id":"d31fd193e7c9ec5c","repo":"apache/cassandra","slug":"duplicate-host-id-found-with-generation","errorCode":null,"errorMessage":"Duplicate host id {} found: {} with generation {} and {} with generation {}, keeping the one with the newest generation","messagePattern":"Duplicate host id (.+?) found: (.+?) with generation (.+?) and (.+?) with generation (.+?), keeping the one with the newest generation","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/java/org/apache/cassandra/tcm/compatibility/GossipHelper.java","lineNumber":502,"sourceCode":"        return false;\n    }\n\n    private static Map<InetAddressAndPort, EndpointState> cleanupDuplicateHostIds(Map<InetAddressAndPort, EndpointState> epstates)\n    {\n        Map<InetAddressAndPort, EndpointState> cleanEpstates = new HashMap<>();\n        Map<String, InetAddressAndPort> seenHostIds = new HashMap<>();\n        for (Map.Entry<InetAddressAndPort, EndpointState> entry : epstates.entrySet())\n        {\n            InetAddressAndPort endpoint = entry.getKey();\n            EndpointState epstate = entry.getValue();\n            String hostIdString = epstate.getApplicationState(HOST_ID).value;\n            if (seenHostIds.containsKey(hostIdString))\n            {\n                int thisGeneration = epstate.getHeartBeatState().getGeneration();\n\n                InetAddressAndPort seenHost = seenHostIds.get(hostIdString);\n                int seenGeneration = epstates.get(seenHost).getHeartBeatState().getGeneration();\n                logger.warn(\"Duplicate host id {} found: {} with generation {} and {} with generation {}, keeping the one with the newest generation\",\n                            hostIdString, seenHost, seenGeneration, endpoint, thisGeneration);\n                if (thisGeneration > seenGeneration)\n                {\n                    cleanEpstates.remove(seenHost);\n                    cleanEpstates.put(endpoint, epstate);\n                    seenHostIds.put(hostIdString, endpoint);\n                }\n            }\n            else\n            {\n                seenHostIds.put(hostIdString, endpoint);\n                cleanEpstates.put(endpoint, epstate);\n            }\n        }\n        return cleanEpstates;\n    }\n}\n","sourceCodeStart":484,"sourceCodeEnd":520,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/tcm/compatibility/GossipHelper.java#L484-L520","documentation":"GossipHelper.cleanupDuplicateHostIds detects two gossip endpoints claiming the same host ID while building clean endpoint states for TCM metadata conversion. It warns with both endpoints and their gossip generations and keeps the endpoint with the newer generation, discarding the stale one.","triggerScenarios":"Gossip ring contains two InetAddressAndPort entries whose EndpointState share one hostIdString, typically after a node was cloned/imaged or IP reassigned, so two live-looking states carry the same HostID; encountered in fromEndpointStates during gossip-to-TCM conversion.","commonSituations":"VM/disk images copied without clearing host ID; IP address recycled to a new node while old endpoint state lingers in gossip; restores of node state from backups on different IPs.","solutions":["Identify which endpoint is genuine (newer generation) and decommission or remove the other from gossip.","Never clone Cassandra node images; generate a fresh host ID (system.local) for each new node.","Run nodetool gossipinfo to inspect duplicate host IDs and confirm which IP currently owns the node.","If the stale entry persists, force-remove it (nodetool remove/assassinate only for truly dead endpoints)."],"exampleFix":"// before\nInetAddressAndPort stale = seenGeneration >= thisGeneration ? endpoint : seenHost;\ncleanEpstates.remove(stale);\n// after (already kept by the code: ensure the surviving node has a unique host ID)\n// regenerate system.local host_id on cloned nodes before joining","handlingStrategy":"validation","validationCode":"// Detect duplicate host IDs before conversion\nMap<String, List<InetAddressAndPort>> byHostId = new HashMap<>();\nepstates.forEach((ep, st) -> {\n    String id = st.getApplicationState(ApplicationState.HOST_ID).value;\n    byHostId.computeIfAbsent(id, k -> new ArrayList<>()).add(ep);\n});\nboolean duplicates = byHostId.values().stream().anyMatch(l -> l.size() > 1);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never clone Cassandra node images or system.local data across nodes.","Audit host IDs with nodetool gossipinfo after IP changes or restores.","Decommission nodes properly instead of discarding them."],"tags":["gossip","tcm","duplicate-host-id","node-clone"],"backgroundTag":"invalid-state-transition","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}