apache/cassandra · error · Transformation.RejectedTransformationException
There are not enough nodes in
Error message
There are not enough nodes in %s datacenter to satisfy replication factor
What it means
Thrown by CMSPlacementStrategy.reconfigure() as a RejectedTransformationException when a datacenter exists but has fewer registered nodes than the requested replication factor, so the CMS placement cannot satisfy the RF there.
Solutions
- Lower the requested RF to at most the node count in each DC
- Add more nodes to the datacenter before reconfiguring
- Remove the under-provisioned DC from the reconfigure request
Example fix
// before (3 nodes in dc1) nodetool cms reconfigure --rf 5 // after nodetool cms reconfigure --rf 3
Defensive patterns
Strategy: validation
Validate before calling
for (Map.Entry<String,Integer> e : requestedRf.entrySet()) {
int size = metadata.directory.allDatacenterEndpoints().get(e.getKey()).size();
if (e.getValue() > size) throw new IllegalArgumentException("RF " + e.getValue() + " > " + size + " nodes in " + e.getKey());
} Try / catch
try { cms.reconfigure(rf); } catch (Transformation.RejectedTransformationException e) { logger.warn("Not enough nodes for RF; reduce RF or add nodes"); } Prevention
- Keep RF <= node count per DC
- Re-check RF settings after scaling down the cluster
- Automate RF sizing from current topology
When it happens
Trigger: reconfigure (via prepareNewCMS/newCms) with an RF per DC greater than the number of live endpoints in that DC from metadata.directory.allDatacenterEndpoints().
Common situations: nodetool cms reconfigure 5 in a 3-node DC; requesting RF for a DC still mid-deployment; stale RF map after scaling the cluster down.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- There are no nodes in
- A node required to move the data consistently is down
- Another sequence of kind
- Can not advance in-progress sequence, since its kind is
- Can not apply in-progress sequence, since its kind is
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/a3c26d6c06093fc2.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/locator/CMSPlacementStrategy.java:75
@VisibleForTesting
public CMSPlacementStrategy(Map<String, Integer> rf, BiFunction<ClusterMetadata, NodeId, Boolean> filter)
{
// todo: verify only test uses with other filter
this.rf = rf;
this.filter = filter;
}
public Set<NodeId> reconfigure(ClusterMetadata metadata)
{
Map<String, ReplicationFactor> rf = new HashMap<>(this.rf.size());
for (Map.Entry<String, Integer> e : this.rf.entrySet())
{
Collection<InetAddressAndPort> nodesInDc = metadata.directory.allDatacenterEndpoints().get(e.getKey());
if (nodesInDc.isEmpty())
throw new IllegalStateException(String.format("There are no nodes in %s datacenter", e.getKey()));
if (nodesInDc.size() < e.getValue())
throw new Transformation.RejectedTransformationException(String.format("There are not enough nodes in %s datacenter to satisfy replication factor", e.getKey()));
rf.put(e.getKey(), ReplicationFactor.fullOnly(e.getValue()));
}
Directory tmpDirectory = metadata.directory;
TokenMap tmpTokenMap = metadata.tokenMap;
for (NodeId peerId : metadata.directory.peerIds())
{
if (!filter.apply(metadata, peerId))
{
tmpDirectory = tmpDirectory.without(metadata.nextEpoch(), peerId);
tmpTokenMap = tmpTokenMap.unassignTokens(peerId);
}
}
// Although MetaStrategy has its own entireRange, it uses a custom partitioner which isn't compatible with
// regular, non-CMS placements. For that reason, we select replicas here using tokens provided by the
// globally configured partitioner. This also has the benefit of making concurrent operations, such asView on GitHub (pinned to 88fd0f6a0e)