{"record":{"id":"a3c26d6c06093fc2","repo":"apache/cassandra","slug":"there-are-not-enough-nodes-in-s-datacenter-to-sat","errorCode":null,"errorMessage":"There are not enough nodes in %s datacenter to satisfy replication factor","messagePattern":"There are not enough nodes in (.+?) datacenter to satisfy replication factor","errorType":"exception","errorClass":"Transformation.RejectedTransformationException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/locator/CMSPlacementStrategy.java","lineNumber":75,"sourceCode":"\n    @VisibleForTesting\n    public CMSPlacementStrategy(Map<String, Integer> rf, BiFunction<ClusterMetadata, NodeId, Boolean> filter)\n    {\n        // todo: verify only test uses with other filter\n        this.rf = rf;\n        this.filter = filter;\n    }\n\n    public Set<NodeId> reconfigure(ClusterMetadata metadata)\n    {\n        Map<String, ReplicationFactor> rf = new HashMap<>(this.rf.size());\n        for (Map.Entry<String, Integer> e : this.rf.entrySet())\n        {\n            Collection<InetAddressAndPort> nodesInDc = metadata.directory.allDatacenterEndpoints().get(e.getKey());\n            if (nodesInDc.isEmpty())\n                throw new IllegalStateException(String.format(\"There are no nodes in %s datacenter\", e.getKey()));\n            if (nodesInDc.size() < e.getValue())\n                throw new Transformation.RejectedTransformationException(String.format(\"There are not enough nodes in %s datacenter to satisfy replication factor\", e.getKey()));\n\n            rf.put(e.getKey(), ReplicationFactor.fullOnly(e.getValue()));\n        }\n\n        Directory tmpDirectory = metadata.directory;\n        TokenMap tmpTokenMap = metadata.tokenMap;\n        for (NodeId peerId : metadata.directory.peerIds())\n        {\n            if (!filter.apply(metadata, peerId))\n            {\n                tmpDirectory = tmpDirectory.without(metadata.nextEpoch(), peerId);\n                tmpTokenMap = tmpTokenMap.unassignTokens(peerId);\n            }\n        }\n\n        // Although MetaStrategy has its own entireRange, it uses a custom partitioner which isn't compatible with\n        // regular, non-CMS placements. For that reason, we select replicas here using tokens provided by the\n        // globally configured partitioner. This also has the benefit of making concurrent operations, such as","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/locator/CMSPlacementStrategy.java#L57-L93","documentation":"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.","triggerScenarios":"reconfigure (via prepareNewCMS/newCms) with an RF per DC greater than the number of live endpoints in that DC from metadata.directory.allDatacenterEndpoints().","commonSituations":"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.","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"],"exampleFix":"// before (3 nodes in dc1)\nnodetool cms reconfigure --rf 5\n\n// after\nnodetool cms reconfigure --rf 3","handlingStrategy":"validation","validationCode":"for (Map.Entry<String,Integer> e : requestedRf.entrySet()) {\n    int size = metadata.directory.allDatacenterEndpoints().get(e.getKey()).size();\n    if (e.getValue() > size) throw new IllegalArgumentException(\"RF \" + e.getValue() + \" > \" + size + \" nodes in \" + e.getKey());\n}","typeGuard":null,"tryCatchPattern":"try { cms.reconfigure(rf); } catch (Transformation.RejectedTransformationException e) { logger.warn(\"Not enough nodes for RF; reduce RF or add nodes\"); }","preventionTips":["Keep RF <= node count per DC","Re-check RF settings after scaling down the cluster","Automate RF sizing from current topology"],"tags":["cms","placement","replication-factor"],"backgroundTag":"value-out-of-range","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}