apache/cassandra · warning

Duplicate host id found: with generation and with…

Error message

Duplicate host id {} found: {} with generation {} and {} with generation {}, keeping the one with the newest generation

What it means

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.

Solutions

  1. Identify which endpoint is genuine (newer generation) and decommission or remove the other from gossip.
  2. Never clone Cassandra node images; generate a fresh host ID (system.local) for each new node.
  3. Run nodetool gossipinfo to inspect duplicate host IDs and confirm which IP currently owns the node.
  4. If the stale entry persists, force-remove it (nodetool remove/assassinate only for truly dead endpoints).

Example fix

// before
InetAddressAndPort stale = seenGeneration >= thisGeneration ? endpoint : seenHost;
cleanEpstates.remove(stale);
// after (already kept by the code: ensure the surviving node has a unique host ID)
// regenerate system.local host_id on cloned nodes before joining
Defensive patterns

Strategy: validation

Validate before calling

// Detect duplicate host IDs before conversion
Map<String, List<InetAddressAndPort>> byHostId = new HashMap<>();
epstates.forEach((ep, st) -> {
    String id = st.getApplicationState(ApplicationState.HOST_ID).value;
    byHostId.computeIfAbsent(id, k -> new ArrayList<>()).add(ep);
});
boolean duplicates = byHostId.values().stream().anyMatch(l -> l.size() > 1);

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/d31fd193e7c9ec5c. Report an issue: GitHub.

Appendix: source

Thrown at src/java/org/apache/cassandra/tcm/compatibility/GossipHelper.java:502

        return false;
    }

    private static Map<InetAddressAndPort, EndpointState> cleanupDuplicateHostIds(Map<InetAddressAndPort, EndpointState> epstates)
    {
        Map<InetAddressAndPort, EndpointState> cleanEpstates = new HashMap<>();
        Map<String, InetAddressAndPort> seenHostIds = new HashMap<>();
        for (Map.Entry<InetAddressAndPort, EndpointState> entry : epstates.entrySet())
        {
            InetAddressAndPort endpoint = entry.getKey();
            EndpointState epstate = entry.getValue();
            String hostIdString = epstate.getApplicationState(HOST_ID).value;
            if (seenHostIds.containsKey(hostIdString))
            {
                int thisGeneration = epstate.getHeartBeatState().getGeneration();

                InetAddressAndPort seenHost = seenHostIds.get(hostIdString);
                int seenGeneration = epstates.get(seenHost).getHeartBeatState().getGeneration();
                logger.warn("Duplicate host id {} found: {} with generation {} and {} with generation {}, keeping the one with the newest generation",
                            hostIdString, seenHost, seenGeneration, endpoint, thisGeneration);
                if (thisGeneration > seenGeneration)
                {
                    cleanEpstates.remove(seenHost);
                    cleanEpstates.put(endpoint, epstate);
                    seenHostIds.put(hostIdString, endpoint);
                }
            }
            else
            {
                seenHostIds.put(hostIdString, endpoint);
                cleanEpstates.put(endpoint, epstate);
            }
        }
        return cleanEpstates;
    }
}

View on GitHub (pinned to 88fd0f6a0e)