{"record":{"id":"f4bf47bfb5650e94","repo":"apache/cassandra","slug":"couldn-t-find-any-matching-sufficient-replica-out","errorCode":null,"errorMessage":"Couldn't find any matching sufficient replica out of ","messagePattern":"Couldn't find any matching sufficient replica out of ","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"critical","filePath":"src/java/org/apache/cassandra/dht/RangeStreamer.java","lineNumber":532,"sourceCode":"                 if (strictEndpoints.stream().filter(Replica::isFull).count() > 1)\n                     throw new AssertionError(\"Expected <= 1 endpoint but found \" + strictEndpoints);\n\n                 //We have to check the source filters here to see if they will remove any replicas\n                 //required for strict consistency\n                 if (!all(strictEndpoints, testSourceFilters))\n                     throw new IllegalStateException(\"Necessary replicas for strict consistency were removed by source filters: \" + buildErrorMessage(sourceFilters, strictEndpoints));\n\n                 //If we are transitioning from transient to full and and the set of replicas for the range is not changing\n                 //we might end up with no endpoints to fetch from by address. In that case we can pick any full replica safely\n                 //since we are already a transient replica and the existing replica remains.\n                 //The old behavior where we might be asked to fetch ranges we don't need shouldn't occur anymore.\n                 //So it's an error if we don't find what we need.\n                 if (strictEndpoints.isEmpty() && toFetch.isTransient())\n                     throw new AssertionError(\"If there are no endpoints to fetch from then we must be transitioning from transient to full for range \" + toFetch);\n\n                 // we now add all potential strict endpoints when building the strictMovements, if we still have no full replicas for toFetch we should fail\n                 if (!any(strictEndpoints, isSufficient))\n                     throw new IllegalStateException(\"Couldn't find any matching sufficient replica out of \" + buildErrorMessage(sourceFilters, movements.get(params).get(toFetch)));\n\n                 sources = strictEndpoints;\n             }\n             else\n             {\n                 //Without strict consistency we have given up on correctness so no point in fetching from\n                 //a random full + transient replica since it's also likely to lose data\n                 //Also apply testSourceFilters that were given to us so we can safely select a single source\n                 sources = sorted.apply(movements.get(params).get(toFetch).filter(and(isSufficient, testSourceFilters)));\n                 //Limit it to just the first possible source, we don't need more than one and downstream\n                 //will fetch from every source we supply\n                 sources = sources.size() > 0 ? sources.subList(0, 1) : sources;\n             }\n\n             // storing range and preferred endpoint set\n             rangesToFetchWithPreferredEndpoints.putAll(toFetch, sources, Conflict.NONE);\n             logger.debug(\"Endpoints to fetch for {} are {}\", toFetch, sources);\n","sourceCodeStart":514,"sourceCodeEnd":550,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/dht/RangeStreamer.java#L514-L550","documentation":"RangeStreamer.calculateRangesToFetchWithPreferredEndpoints() requires, under strict consistency, at least one sufficient (full-data-capable) replica among the strict endpoints for each range. If none of the candidate strict replicas is sufficient to serve the full range, it throws IllegalStateException listing the replicas that were considered.","triggerScenarios":"fetchMap() with useStrictConsistency=true where every candidate endpoint for a range fails the isSufficient predicate — typically all candidates are transient replicas or are filtered/down.","commonSituations":"Bootstrapping into a cluster where the only full replica for a range is down; transient replication setups where both full replicas are excluded by source filters; repair backlog leaving no healthy full replica to stream from.","solutions":["Bring up the full replicas for the affected range and rerun the bootstrap/rebuild","Run `nodetool repair` on the range/keyspace to restore a full replica before streaming","Broaden source filters so a full replica is eligible","Temporarily disable strict consistency if partial-data risk is acceptable"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if (strictEndpoints.stream().noneMatch(r -> r.isFull() && isSufficient.test(r)))\n    throw new IllegalStateException(\"No sufficient full replica for \" + toFetch + \"; run repair first\");","typeGuard":null,"tryCatchPattern":"try { streamer.fetch(); } catch (IllegalStateException e) { if (e.getMessage().startsWith(\"Couldn't find any matching sufficient replica\")) { runRepair(keyspace); retry(); } else throw e; }","preventionTips":["Keep at least one healthy full replica per range (avoid RF barely above transient losses)","Run repair regularly with transient replication enabled","Check replica liveness before initiating bootstrap"],"tags":["streaming","strict-consistency","transient-replication","replicas"],"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"}