{"record":{"id":"01f8fef8a89f570b","repo":"apache/cassandra","slug":"readsizeabortexception","errorCode":null,"errorMessage":"ReadSizeAbortException","messagePattern":"ReadSizeAbortException","errorType":"exception","errorClass":"ReadSizeAbortException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/service/reads/thresholds/WarningsSnapshot.java","lineNumber":114,"sourceCode":"    @VisibleForTesting\n    WarningsSnapshot merge(WarningsSnapshot other)\n    {\n        if (other == null || other == EMPTY)\n            return this;\n        return WarningsSnapshot.create(tombstones.merge(other.tombstones),\n                                       localReadSize.merge(other.localReadSize),\n                                       rowIndexReadSize.merge(other.rowIndexReadSize),\n                                       indexReadSSTablesCount.merge(other.indexReadSSTablesCount));\n    }\n\n    public void maybeAbort(ReadCommand command, ConsistencyLevel cl, int received, int blockFor, boolean isDataPresent, Map<InetAddressAndPort, RequestFailureReason> failureReasonByEndpoint)\n    {\n        if (!tombstones.aborts.instances.isEmpty())\n            throw new TombstoneAbortException(tombstoneAbortMessage(tombstones.aborts.instances.size(), tombstones.aborts.maxValue, command.toCQLString()), tombstones.aborts.instances.size(), tombstones.aborts.maxValue, isDataPresent,\n                                              cl, received, blockFor, failureReasonByEndpoint);\n\n        if (!localReadSize.aborts.instances.isEmpty())\n            throw new ReadSizeAbortException(localReadSizeAbortMessage(localReadSize.aborts.instances.size(), localReadSize.aborts.maxValue, command.toCQLString()),\n                                             cl, received, blockFor, isDataPresent, failureReasonByEndpoint);\n\n        if (!rowIndexReadSize.aborts.instances.isEmpty())\n            throw new ReadSizeAbortException(rowIndexReadSizeAbortMessage(rowIndexReadSize.aborts.instances.size(), rowIndexReadSize.aborts.maxValue, command.toCQLString()),\n                                             cl, received, blockFor, isDataPresent, failureReasonByEndpoint);\n\n        if (!indexReadSSTablesCount.aborts.instances.isEmpty())\n            throw new QueryReferencesTooManyIndexesAbortException(tooManyIndexesReadAbortMessage(indexReadSSTablesCount.aborts.instances.size(), indexReadSSTablesCount.aborts.maxValue, command.toCQLString()),\n                                                                  indexReadSSTablesCount.aborts.instances.size(),\n                                                                  indexReadSSTablesCount.aborts.maxValue,\n                                                                  isDataPresent,\n                                                                  cl, received, blockFor, failureReasonByEndpoint);\n    }\n\n    @VisibleForTesting\n    public static String tombstoneAbortMessage(int nodes, long tombstones, String cql)\n    {\n        return String.format(\"%s nodes scanned over %s tombstones and aborted the query %s (see tombstone_failure_threshold)\", nodes, tombstones, cql);","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/service/reads/thresholds/WarningsSnapshot.java#L96-L132","documentation":"WarningsSnapshot.maybeAbort throws ReadSizeAbortException when the accumulated read material exceeds an abort threshold: either local read size (bytes of local reads) or row index-read size. The read is aborted server-side to prevent unbounded memory/CPU consumption on oversized reads.","triggerScenarios":"A read command's local read bytes exceed local_read_size_abort_threshold, or row-index lookups exceed row_index_read_size_abort_threshold (e.g. querying a huge partition or doing many row-index jumps); awaitResults invokes maybeAbort with abort instances recorded.","commonSituations":"Single very large partitions (MBs/GBs) queried fully; thousands of rows fetched via secondary index; defaults too strict after upgrading (thresholds added in newer versions); analytics-style batch reads on wide partitions.","solutions":["Split the read: use token/partition ranges or LIMIT and paginate instead of reading a whole huge partition","Raise local_read_size_fail_threshold / row_index_read_size_fail_threshold in cassandra.yaml if the reads are legitimate","Redesign the data model to bucket large partitions into smaller ones","Enable tracing on the query to see which partition/read triggers the size abort, then target that partition"],"exampleFix":"// before\nSELECT * FROM ks.events WHERE id = 'big-partition';\n// after\nSELECT * FROM ks.events WHERE id = 'big-partition' AND bucket = 3;  // bucketed partition","handlingStrategy":"try-catch","validationCode":"// Pre-flight: check partition size before a full read\n// shell: nodetool tablehistograms ks tbl  — 'Partition size' p99 above local_read_size_warn_threshold signals risk","typeGuard":null,"tryCatchPattern":"try {\n  return session.execute(widePartitionQuery);\n} catch (e) {\n  if (e instanceof ReadSizeAbortException) {\n    logger.warn('read size abort; falling back to paginated/ranged read', e);\n    return paginatedRead(query, pageSize); // fallback strategy\n  }\n  throw e;\n}","preventionTips":["Design partitions to stay well under read size thresholds (bucket large entities)","Use pagination and LIMIT instead of full-partition reads","Alert on read_size warn-threshold log lines before aborts occur","Review thresholds after Cassandra upgrades since size-abort defaults may be new/stricter"],"tags":["read-path","aborted-query","large-partition","thresholds"],"backgroundTag":"read-size-limit-exceeded","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"}