apache/cassandra · warning

Attempted to release storage-attached index segment builder

Error message

Attempted to release storage-attached index segment builder memory after builder marked inactive.

What it means

This warning is logged by SegmentBuilder.release when release() is called on a builder whose active flag is already false, meaning its memory was already released against the SAI memory limiter and ACTIVE_BUILDER_COUNT was already decremented. The call is a no-op (it just returns the limiter's current usage), but it signals a double-release or a release after the builder was already finalized during flush. Memory accounting remains correct; the warning is a lifecycle-management bug signal.

Source

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

     * This method does three things:
     * <p>
     * 1. It decrements active builder count and updates the global minimum flush size to reflect that.
     * 2. It releases the builder's memory against its limiter.
     * 3. It defensively marks the builder inactive to make sure nothing bad happens if we try to close it twice.
     *
     * @return the number of bytes used by the memory limiter after releasing this builder
     */
    public long release()
    {
        if (active)
        {
            minimumFlushBytes = limiter.limitBytes() / ACTIVE_BUILDER_COUNT.getAndDecrement();
            long used = limiter.decrement(totalBytesAllocated);
            active = false;
            return used;
        }

        logger.warn(index.identifier().logMessage("Attempted to release storage-attached index segment builder memory after builder marked inactive."));
        return limiter.currentBytesUsed();
    }

    public abstract boolean isEmpty();

    protected abstract long addInternal(ByteBuffer term, int segmentRowId);

    protected abstract SegmentMetadata.ComponentMetadataMap flushInternal(IndexDescriptor indexDescriptor) throws IOException;

    public int getRowCount()
    {
        return rowCount;
    }

    /**
     * @return true if next SSTable row ID exceeds max segment row ID
     */
    public boolean exceedsSegmentLimit(long ssTableRowId)

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Guard the release call with an ownership/flag in the caller so release() runs exactly once (or rely on the builder's own active flag as the guard)
  2. Audit the flush/close path so release happens in a single finally block per builder rather than from multiple cleanup sites
  3. If reproducible after an upgrade, rebuild the index and report with a thread dump/stack trace to the Cassandra community as a possible lifecycle bug

Example fix

// before
segmentBuilder.release();
segmentBuilder.release(); // double release in error path
// after
if (segmentBuilder != null && released.compareAndSet(false, true))
    segmentBuilder.release();
Defensive patterns

Strategy: validation

Validate before calling

// check before releasing
if (segmentBuilder.isActive())
    segmentBuilder.release();

Prevention

When it happens

Trigger: Calling release() twice on the same SegmentBuilder, or calling release() after flush completed and the builder was already marked inactive; typically from index builder cleanup paths racing with the flush-and-release sequence.

Common situations: A failed or retried flush path where cleanup code runs both in an error handler and in the normal close path; concurrent index drops during flush causing duplicate release calls; custom patches or upgrades where the builder lifecycle ordering changed.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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