apache/cassandra · error · NotCMSException
This node is not in the CMS, can't generate a consistent…
Error message
This node is not in the CMS, can't generate a consistent log fetch response to
What it means
FetchCMSLog.doVerb handles requests for the cluster metadata change log. When the request sets consistentFetch, the responder must be a current CMS member to produce a linearizable (consistent) log state; otherwise it throws NotCMSException. The message includes the requesting peer address. Consistent fetches require the CMS's authoritative view, so a non-member node must refuse.
Solutions
- Re-discover current CMS membership (ClusterMetadataService.currentCMS or placement info) and send the consistent fetch to a node that is a current CMS member.
- If the fetcher is itself joining/rejoining, wait until it is registered or use a non-consistent fetch (consistentFetch=false) for bootstrap catch-up.
- Refresh stale routing/membership caches on the requesting node so requests stop targeting ex-CMS members.
- Retry after CMS reconfiguration completes; transient refusal during placement changes is expected.
Example fix
// caller-side: pick a CMS member for consistent fetch
InetAddressAndPort cms = ClusterMetadataService.instance().currentCMS();
if (!ClusterMetadataService.instance().isCurrentMember(peer))
peer = cms; // before sending FetchCMSLog with consistentFetch = true Defensive patterns
Strategy: validation
Validate before calling
if (!ClusterMetadataService.instance().isCurrentMember(target))
target = ClusterMetadataService.instance().currentCMS(); // re-route consistent fetch to a CMS member Try / catch
try { logState = peer.fetchLogEntries(...); } catch (NotCMSException e) { logState = fetchFromCurrentCMS(); } Prevention
- Resolve current CMS membership dynamically instead of caching peer addresses
- Re-route consistent fetches to ClusterMetadataService.currentCMS()
- Use non-consistent fetches for bootstrap catch-up from non-CMS peers
When it happens
Trigger: A peer sends FetchCMSLog with consistentFetch=true to a node for which ClusterMetadataService.instance().isCurrentMember(FBUtilities.getBroadcastAddressAndPort()) is false at FetchCMSLog.java:112.
Common situations: Client/peer pinned its CMS discovery to a node that was later removed from the CMS placement (e.g. after reconfiguration or restart); mixed-version or membership-change races where routing tables are stale; nodes catching up via a peer that is no longer in the CMS.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- Got mismatching cluster metadatas. Check logs on peers
- Mismatching metadata id in survey request from
- Addresses differ: !=
- Attempting to load denylist and not enough nodes are…
- Bad CMS state:
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/cd13cc67d7114f9e.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/tcm/FetchCMSLog.java:112
public Handler()
{
this(DistributedMetadataLogKeyspace::getLogState);
}
public Handler(BiFunction<Epoch, Boolean, LogState> logStateSupplier)
{
this.logStateSupplier = logStateSupplier;
}
public void doVerb(Message<FetchCMSLog> message) throws IOException
{
FetchCMSLog request = message.payload;
if (logger.isTraceEnabled())
logger.trace("Received log fetch request {} from {}: start = {}, current = {}", request, message.from(), message.payload.lowerBound, ClusterMetadata.current().epoch);
if (request.consistentFetch && !ClusterMetadataService.instance().isCurrentMember(FBUtilities.getBroadcastAddressAndPort()))
throw new NotCMSException("This node is not in the CMS, can't generate a consistent log fetch response to " + message.from());
// If both we and the other node believe it should be caught up with a linearizable read
boolean consistentFetch = request.consistentFetch && !ClusterMetadataService.instance().isCurrentMember(message.from());
LogState delta = logStateSupplier.apply(message.payload.lowerBound, consistentFetch);
TCMMetrics.instance.cmsLogEntriesServed(message.payload.lowerBound, delta.latestEpoch());
logger.info("Responding to {}({}) with log delta: {}", message.from(), request, delta);
MessagingService.instance().send(message.responseWith(delta), message.from());
}
}
}
View on GitHub (pinned to 88fd0f6a0e)