{"record":{"id":"834c2bcc2e56b9d0","repo":"apache/cassandra","slug":"unable-to-find-sufficient-sources-for-streaming-ra-834c2b","errorCode":null,"errorMessage":"Unable to find sufficient sources for streaming range  in keyspace  with RF=1. Ensure this keyspace contains replicas in the source datacenter.","messagePattern":"Unable to find sufficient sources for streaming range  in keyspace  with RF=1\\. Ensure this keyspace contains replicas in the source datacenter\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"critical","filePath":"src/java/org/apache/cassandra/dht/RangeStreamer.java","lineNumber":572,"sourceCode":"\n             /*\n              * When we move forwards (shrink our bucket) we are the one losing a range and no one else loses\n              * from that action (we also don't gain). When we move backwards there are two people losing a range. One is a full replica\n              * and the other is a transient replica. So we must need fetch from two places in that case for the full range we gain.\n              * For a transient range we only need to fetch from one.\n              */\n             if (useStrictConsistency && addressList.size() > 1 && (addressList.filter(Replica::isFull).size() > 1 || addressList.filter(Replica::isTransient).size() > 1))\n                 throw new IllegalStateException(String.format(\"Multiple strict sources found for %s, sources: %s\", toFetch, addressList));\n\n             //We must have enough stuff to fetch from\n             if (!any(addressList, isSufficient))\n             {\n                 if (strat.getReplicationFactor().allReplicas == 1)\n                 {\n                     if (useStrictConsistency)\n                     {\n                         logger.warn(\"A node required to move the data consistently is down\");\n                         throw new IllegalStateException(\"Unable to find sufficient sources for streaming range \" + toFetch + \" in keyspace \" + keyspace + \" with RF=1. \" +\n                                                         \"Ensure this keyspace contains replicas in the source datacenter.\");\n                     }\n                     else\n                         logger.warn(\"Unable to find sufficient sources for streaming range {} in keyspace {} with RF=1. \" +\n                                     \"Keyspace might be missing data.\", toFetch, keyspace);\n                 }\n                 else\n                 {\n                     if (useStrictConsistency)\n                         logger.warn(\"A node required to move the data consistently is down\");\n                     throw new IllegalStateException(\"Unable to find sufficient sources for streaming range \" + toFetch + \" in keyspace \" + keyspace);\n                 }\n             }\n         }\n         return rangesToFetchWithPreferredEndpoints.build();\n     }\n\n    /**","sourceCodeStart":554,"sourceCodeEnd":590,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/dht/RangeStreamer.java#L554-L590","documentation":"When a range has no sufficient source and the keyspace replication factor is 1, RangeStreamer cannot stream from anywhere. Under strict consistency it throws IllegalStateException telling the operator the source datacenter lacks replicas for this keyspace (RF=1 means the single replica is the only possible source); without strict consistency it only logs a warning that data may be missing.","triggerScenarios":"fetchMap()/calculateRangesToFetchWithPreferredEndpoints() with useStrictConsistency=true where a range's sole replica is unavailable (down or filtered out) and strat.getReplicationFactor().allReplicas == 1.","commonSituations":"Rebuilding a node in a DC where a SimpleStrategy RF=1 keyspace has its only replica elsewhere (e.g. rebuild -- dc2 for a keyspace only replicated in dc1); bootstrapping while the single replica host is down; RF=1 keyspaces during decommission/replace.","solutions":["Ensure the keyspace has a replica in the source datacenter: increase RF or ALTER KEYSPACE to NetworkTopologyStrategy with RF>=1 per DC, then run repair before rebuilding","Start the down single replica and rerun the operation","Run rebuild/bootstrap without a DC restriction (or with `nodetool rebuild -- <dc-holding-the-replica>`) so the single replica is reachable","If data loss is acceptable, proceed without strict consistency (warning-only path) and run repair afterwards"],"exampleFix":"// before\nALTER KEYSPACE ks WITH replication = {'class':'NetworkTopologyStrategy','dc1':1};\nnodetool rebuild -- dc2\n// after\nALTER KEYSPACE ks WITH replication = {'class':'NetworkTopologyStrategy','dc1':1,'dc2':1};\nnodetool repair ks\nnodetool rebuild -- dc1","handlingStrategy":"validation","validationCode":"// Verify source DC holds replicas before rebuilding\nKeyspaceMetadata ks = Schema.instance.getKeyspaceMetadata(keyspace);\nif (ks.params.replication.asStrategy().getReplicationFactor(sourceDc).allReplicas < 1)\n    throw new IllegalArgumentException(\"Keyspace \" + keyspace + \" has no replica in source DC \" + sourceDc);","typeGuard":null,"tryCatchPattern":"try { streamer.fetch(); } catch (IllegalStateException e) { if (e.getMessage().contains(\"with RF=1\")) { fixReplicationOrRestartReplica(); retry(); } else throw e; }","preventionTips":["Avoid RF=1 keyspaces in clusters that undergo rebuilds/replaces","Use NetworkTopologyStrategy with RF>=1 per DC","Confirm all single replicas are live before topology operations","Run repair after RF increases so new DCs actually have data"],"tags":["streaming","rf1","replication","datacenter"],"backgroundTag":"resource-not-found","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}