apache/cassandra · warning

States differ: {} != {}

Error message

States differ: {} != {}

What it means

WARN log from Directory.dumpDiff(Directory) reporting that the states maps (NodeId to NodeState: e.g. REGISTERED, BOOTSTRAPPING, LEFT) differ between two Directory snapshots. Divergent node states mean the two cluster views disagree on each member's lifecycle phase, which changes how joins and leaves are handled. Diagnostic output, not an exception.

Source

Thrown at src/java/org/apache/cassandra/tcm/membership/Directory.java:916

        {
            logger.warn("nextId differ: {} != {}", nextId, other.nextId);
        }
        if (!Objects.equals(lastModified, other.lastModified))
        {
            logger.warn("Last modified differ: {} != {}", lastModified, other.lastModified);
        }
        if (!Objects.equals(peers, other.peers))
        {
            logger.warn("Peers differ: {} != {}", peers, other.peers);
            dumpDiff(logger, peers, other.peers);
        }
        if (!Objects.equals(locations, other.locations))
        {
            logger.warn("Locations differ: {} != {}", locations, other.locations);
        }
        if (!Objects.equals(states, other.states))
        {
            logger.warn("States differ: {} != {}", states, other.states);
            dumpDiff(logger, states, other.states);
        }
        if (!Objects.equals(endpointsByDC, other.endpointsByDC))
        {
            logger.warn("Endpoints by dc differ: {} != {}", endpointsByDC, other.endpointsByDC);
            dumpDiff(logger, endpointsByDC.asMap(), other.endpointsByDC.asMap());
        }
        if (!Objects.equals(racksByDC, other.racksByDC))
        {
            logger.warn("Racks by dc differ: {} != {}", racksByDC, other.racksByDC);
        }
        if (!Objects.equals(versions, other.versions))
        {
            logger.warn("Versions differ: {} != {}", versions, other.versions);
            dumpDiff(logger, versions, other.versions);
        }
        if (!Objects.equals(addresses, other.addresses))
        {

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Identify which node IDs have differing states and let the outstanding lifecycle operation (bootstrap/decommission) complete or be cancelled via its TCM transformation
  2. Replay missed cluster metadata events on the stale node to converge states
  3. If a lifecycle operation is stuck, use the appropriate repair tooling (e.g. cancel/retry the transformation) rather than hand-editing state
  4. Restart the diverging node to reload cluster metadata from the CMS
Defensive patterns

Strategy: validation

Validate before calling

// Ensure no node is mid-lifecycle in either view before comparing states
boolean anyTransient = dir.states().values().stream()
    .anyMatch(s -> s == NodeState.BOOTSTRAPPING || s == NodeState.DECOMMISSIONING);
if (!anyTransient)
    dir.dumpDiff(other); // transient states make diffs noisy

Prevention

When it happens

Trigger: dumpDiff(other) when Objects.equals(states, other.states) is false; a node mid-bootstrap appears as BOOTSTRAPPING in one view and REGISTERED/LEFT in the other; a decommission completed on one side only.

Common situations: Interrupted bootstrap or decommission leaving one node's view mid-transition; a node missed the transformation committing the state change; dtest assertions diffing directories across cluster members.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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