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
- Identify which node IDs have differing states and let the outstanding lifecycle operation (bootstrap/decommission) complete or be cancelled via its TCM transformation
- Replay missed cluster metadata events on the stale node to converge states
- If a lifecycle operation is stuck, use the appropriate repair tooling (e.g. cancel/retry the transformation) rather than hand-editing state
- 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
- Let bootstrap/decommission transformations fully complete before diffing directories
- Monitor for nodes stuck in transitional NodeStates
- Replay missed metadata commits on nodes with outdated state maps
- Use proper cancel/retry tooling for interrupted lifecycle operations instead of manual edits
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
- nextId differ: {} != {}
- Last modified differ: {} != {}
- Peers differ: {} != {}
- Locations differ: {} != {}
- Endpoints by dc differ: {} != {}
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/43be9da4035ee31b.
Report an issue: GitHub.