{"record":{"id":"e4e4702d8d18aa1a","repo":"apache/cassandra","slug":"unable-to-find-sufficient-sources-for-streaming-ra-e4e470","errorCode":null,"errorMessage":"Unable to find sufficient sources for streaming range \" + range + \" in keyspace \" + keyspace","messagePattern":"Unable to find sufficient sources for streaming range \" \\+ range \\+ \" in keyspace \" \\+ keyspace","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"critical","filePath":"src/java/org/apache/cassandra/dht/RangeFetchMapCalculator.java","lineNumber":342,"sourceCode":"            if (trivialRanges.contains(range))\n            {\n                logger.debug(\"Not optimising trivial range {} for keyspace {}\", range, keyspace);\n                continue;\n            }\n\n            final RangeVertex rangeVertex = new RangeVertex(range);\n\n            //Try to only add source endpoints from same DC\n            boolean sourceFound = addEndpoints(capacityGraph, rangeVertex, true);\n\n            if (!sourceFound)\n            {\n                logger.info(\"Using other DC endpoints for streaming for range: {} and keyspace {}\", range, keyspace);\n                sourceFound = addEndpoints(capacityGraph, rangeVertex, false);\n            }\n\n            if (!sourceFound)\n                throw new IllegalStateException(\"Unable to find sufficient sources for streaming range \" + range + \" in keyspace \" + keyspace);\n\n        }\n\n        return capacityGraph;\n    }\n\n    /**\n     * Create edges with infinite capacity b/w range vertex and all its source endpoints which clear the filters\n     * @param capacityGraph The Capacity graph on which changes are made\n     * @param rangeVertex The range for which we need to add all its source endpoints\n     * @param localDCCheck Should add source endpoints from local DC only\n     * @return If we were able to add atleast one source for this range after applying filters to endpoints\n     */\n    private boolean addEndpoints(MutableCapacityGraph<Vertex, Integer> capacityGraph, RangeVertex rangeVertex, boolean localDCCheck)\n    {\n        boolean sourceFound = false;\n        Replicas.temporaryAssertFull(rangesWithSources.get(rangeVertex.getRange()));\n        for (Replica replica : rangesWithSources.get(rangeVertex.getRange()))","sourceCodeStart":324,"sourceCodeEnd":360,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/dht/RangeFetchMapCalculator.java#L324-L360","documentation":"RangeFetchMapCalculator.getGraph() constructs a flow/capacity graph for non-trivial (pending) range movements and solves for fetch mappings. If, for a given range, addEndpoints() cannot find any live, filter-passing source endpoint even after allowing other-DC endpoints, it throws IllegalStateException — the streaming plan is infeasible.","triggerScenarios":"Calling getRangeFetchMapForNonTrivialRanges via getRangeFetchMap during bootstrap/replace/move where a pending range has no available live replica sources after source filters and DC-preference are applied.","commonSituations":"Range movements (nodetool move/decommission mid-flight) where the previous owner is down; strict endpoint-snitch configs where all replicas for a pending range sit in unavailable hosts; source filters (e.g. only-stream-from-same-DC) excluding everything.","solutions":["Ensure all replicas owning the pending ranges are alive (nodetool status) before resuming the operation","Retry the operation after the failed node recovers, or force a rebuild from a healthy source DC (nodetool rebuild -- <dc>)","Review sourceFilters (RangeStreamer source filter configuration) and relax them so at least one replica qualifies","Re-run repair to converge data if the operation failed mid-move, then retry"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"for (Range<Token> pending : pendingRanges)\n    if (tokenMetadata.getReplicasForReading(pending).stream().noneMatch(r -> failureDetector.isAlive(r.endpoint())))\n        throw new IllegalStateException(\"No live source for pending range \" + pending);","typeGuard":null,"tryCatchPattern":"try { streamer.fetch(); } catch (IllegalStateException e) { if (e.getMessage().contains(\"Unable to find sufficient sources for streaming range\")) { waitForReplicasUp(); retryFetch(); } else throw e; }","preventionTips":["Avoid overlapping move/decommission/bootstrap operations","Keep FailureDetector healthy (gossip) so live replicas are recognized","Relax same-DC-only streaming filters when cross-DC fallback is desired"],"tags":["streaming","bootstrap","flow-graph","replication"],"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"}