{"record":{"id":"3b15341847465b16","repo":"apache/cassandra","slug":"no-rows-to-index-during-flush-of-sstable","errorCode":null,"errorMessage":"No rows to index during flush of SSTable {}.","messagePattern":"No rows to index during flush of SSTable (.+?)\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"info","filePath":"src/java/org/apache/cassandra/index/sai/disk/v1/segment/SegmentBuilder.java","lineNumber":161,"sourceCode":"    }\n\n    private SegmentBuilder(StorageAttachedIndex index, NamedMemoryLimiter limiter)\n    {\n        this.index = index;\n        this.limiter = limiter;\n        lastValidSegmentRowID = testLastValidSegmentRowId >= 0 ? testLastValidSegmentRowId : LAST_VALID_SEGMENT_ROW_ID;\n\n        minimumFlushBytes = limiter.limitBytes() / ACTIVE_BUILDER_COUNT.incrementAndGet();\n    }\n\n    public SegmentMetadata flush(IndexDescriptor indexDescriptor) throws IOException\n    {\n        assert !flushed : \"Cannot flush an already flushed segment\";\n        flushed = true;\n\n        if (getRowCount() == 0)\n        {\n            logger.warn(index.identifier().logMessage(\"No rows to index during flush of SSTable {}.\"), indexDescriptor.sstableDescriptor);\n            return null;\n        }\n\n        SegmentMetadata.ComponentMetadataMap indexMetas = flushInternal(indexDescriptor);\n\n        return new SegmentMetadata(segmentRowIdOffset, rowCount, minSSTableRowId, maxSSTableRowId, minKey, maxKey, minTerm, maxTerm, indexMetas);\n    }\n\n    public long add(ByteBuffer term, PrimaryKey key, long sstableRowId)\n    {\n        assert !flushed : \"Cannot add to a flushed segment.\";\n        assert sstableRowId >= maxSSTableRowId;\n        minSSTableRowId = minSSTableRowId < 0 ? sstableRowId : minSSTableRowId;\n        maxSSTableRowId = sstableRowId;\n\n        assert maxKey == null || maxKey.compareTo(key) <= 0;\n        if (minKey == null)\n            minKey = key;","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/index/sai/disk/v1/segment/SegmentBuilder.java#L143-L179","documentation":"During SAI flush, SegmentBuilder.flush logs this warning when a segment builder contains zero indexed rows (getRowCount() == 0). The builder is marked flushed and flushInternal is skipped; the method returns null so no SegmentMetadata is produced and no segment files are written for this SSTable. It is a benign indicator that nothing was written to the segment, usually harmless but can indicate an indexing or pre-selection problem upstream.","triggerScenarios":"Calling flush() on a SegmentBuilder that had zero rows added - e.g. all rows in the flush were filtered out or contained no indexable values for the column, or a per-column index builder was created for an SSTable whose data matched no rows.","commonSituations":"Flushing an SSTable where every row was TTL-expired or tombstoned before indexing; indexing a column that is null/empty in every row; compaction of fully expired SSTables routed through the index writer path.","solutions":["Confirm with a direct CQL query whether the column really has no indexable values in this SSTable; if so the warning is expected and can be ignored","If rows should have been indexed, check for tombstone/expiry issues (gc_grace_seconds, default_time_to_live) affecting the flushed data","Verify the index is defined on the correct column and table; if rows exist but are not indexed, upgrade to a fixed Cassandra version and rebuild the index"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// before flushing, skip the write path when the segment is known empty\nif (segmentBuilder.getRowCount() == 0)\n{\n    logger.info(\"Skipping empty segment flush for {}\", sstable);\n    return null;\n}","typeGuard":null,"tryCatchPattern":"try { return segmentBuilder.flush(descriptor); }\ncatch (IOException e) { throw new IOError(e); } // empty-segment case returns null by design; no catch needed","preventionTips":["Treat a null return from flush as 'no segment written', not an error, in downstream metadata handling","Investigate only if rows exist in the SSTable but no segment is ever produced (possible tombstone/expiry or index-definition issue)","Test index behavior with fully expired/tombstoned data sets"],"tags":["sai","index","flush","empty-data"],"backgroundTag":"empty-result-set","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}