apache/cassandra · info

No rows to index during flush of SSTable {}.

Error message

No rows to index during flush of SSTable {}.

What it means

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.

Source

Thrown at src/java/org/apache/cassandra/index/sai/disk/v1/segment/SegmentBuilder.java:161

    }

    private SegmentBuilder(StorageAttachedIndex index, NamedMemoryLimiter limiter)
    {
        this.index = index;
        this.limiter = limiter;
        lastValidSegmentRowID = testLastValidSegmentRowId >= 0 ? testLastValidSegmentRowId : LAST_VALID_SEGMENT_ROW_ID;

        minimumFlushBytes = limiter.limitBytes() / ACTIVE_BUILDER_COUNT.incrementAndGet();
    }

    public SegmentMetadata flush(IndexDescriptor indexDescriptor) throws IOException
    {
        assert !flushed : "Cannot flush an already flushed segment";
        flushed = true;

        if (getRowCount() == 0)
        {
            logger.warn(index.identifier().logMessage("No rows to index during flush of SSTable {}."), indexDescriptor.sstableDescriptor);
            return null;
        }

        SegmentMetadata.ComponentMetadataMap indexMetas = flushInternal(indexDescriptor);

        return new SegmentMetadata(segmentRowIdOffset, rowCount, minSSTableRowId, maxSSTableRowId, minKey, maxKey, minTerm, maxTerm, indexMetas);
    }

    public long add(ByteBuffer term, PrimaryKey key, long sstableRowId)
    {
        assert !flushed : "Cannot add to a flushed segment.";
        assert sstableRowId >= maxSSTableRowId;
        minSSTableRowId = minSSTableRowId < 0 ? sstableRowId : minSSTableRowId;
        maxSSTableRowId = sstableRowId;

        assert maxKey == null || maxKey.compareTo(key) <= 0;
        if (minKey == null)
            minKey = key;

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. 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
  2. If rows should have been indexed, check for tombstone/expiry issues (gc_grace_seconds, default_time_to_live) affecting the flushed data
  3. 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
Defensive patterns

Strategy: validation

Validate before calling

// before flushing, skip the write path when the segment is known empty
if (segmentBuilder.getRowCount() == 0)
{
    logger.info("Skipping empty segment flush for {}", sstable);
    return null;
}

Try / catch

try { return segmentBuilder.flush(descriptor); }
catch (IOException e) { throw new IOError(e); } // empty-segment case returns null by design; no catch needed

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/3b15341847465b16. Report an issue: GitHub.