apache/cassandra · warning · IllegalStateException
%s is not currently joining the CMS
Error message
%s is not currently joining the CMS
What it means
CMSMembership.cancelJoining removes a node from the joiningMembers set. It throws IllegalStateException if the id is not currently in that set, because there is no in-flight join to cancel — the transformation would be a no-op or hide a state bug.
Source
Thrown at src/java/org/apache/cassandra/tcm/CMSMembership.java:150
public Set<NodeId> fullMembers()
{
return fullMembers;
}
public CMSMembership startJoining(NodeId id)
{
if (joiningMembers.contains(id))
throw new IllegalStateException(id + " is already joining the CMS");
if (fullMembers.contains(id))
throw new IllegalStateException(id + " has already fully joined the CMS");
return new CMSMembership(lastModified, fullMembers, joiningMembers.with(id));
}
public CMSMembership cancelJoining(NodeId id)
{
if (!joiningMembers.contains(id))
throw new IllegalStateException(id + " is not currently joining the CMS");
if (fullMembers.contains(id))
throw new IllegalStateException(id + " has already fully joined the CMS");
return new CMSMembership(lastModified, fullMembers, joiningMembers.without(id));
}
public CMSMembership finishJoining(NodeId id)
{
if (!joiningMembers.contains(id))
throw new IllegalStateException(id + " is not currently joining the CMS");
if (fullMembers.contains(id))
throw new IllegalStateException(id + " has already fully joined the CMS");
return new CMSMembership(lastModified, fullMembers.with(id), joiningMembers.without(id));
}
public CMSMembership leave(NodeId id)
{View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Before cancelling, read the node's current CMS state from the latest epoch and only cancel if it is genuinely in joiningMembers
- Handle the exception as an expected race in join timeout logic: re-read metadata and decide based on current state (finished joining? then nothing to do)
- Serialize join lifecycle operations through a single owner so cancel cannot race finishJoining
- If the join state is stuck inconsistent, fix it via explicit finishJoining or a fresh startJoining rather than cancelJoining
Example fix
// before
membership = cms.cancelJoining(nodeId); // throws if not joining
// after
if (cms.joiningMembers().contains(nodeId))
membership = cms.cancelJoining(nodeId); Defensive patterns
Strategy: validation
Validate before calling
if (!membership.joiningMembers().contains(nodeId)) return; // nothing to cancel
Prevention
- Verify the node is still in joiningMembers in the latest epoch before cancelling
- Guard timeout handlers against cancelling completed joins
- Centralize join lifecycle transitions in one owner
When it happens
Trigger: Applying a cancelJoining transformation for a NodeId absent from joiningMembers — cancelling a join that already finished (or failed) via finishJoining, was never started, or whose state was already rolled forward/back in a later epoch.
Common situations: Timeout handling that cancels a join after it already completed; running cleanup for joins on wrong/stale epoch snapshots; double-cancellation from two failure handlers.
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
- %s is already joining the CMS
- %s has already fully joined the CMS
- has already fully joined the CMS
- Node %s is not a CMS member in epoch %s; members=%s
- Could not catch up to epoch %s even after fetching log from
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/45a48aa4f6973334.
Report an issue: GitHub.