apache/cassandra · warning

Couldn't acquire reference to the SSTable {}. It may have be

Error message

Couldn't acquire reference to the SSTable {}. It may have been removed.

What it means

During SAI index builds, StorageAttachedIndexBuilder.indexSSTable attempts sstable.tryRef() to acquire a reference to the SSTableReader before opening the data file. tryRef() returns null when the SSTable has already been released/compacted away, meaning another lifecycle operation (compaction, truncation, repair cleanup) removed the SSTable while the index build was waiting in the queue. The builder logs a warning and returns false so the build can be rescheduled or skipped, rather than crashing.

Source

Thrown at src/java/org/apache/cassandra/index/sai/StorageAttachedIndexBuilder.java:142

    private String logMessage(String message)
    {
        return String.format("[%s.%s.*] %s", metadata.keyspace, metadata.name, message);
    }

    /**
     * @return true if index build should be stopped
     */
    private boolean indexSSTable(SSTableReader sstable, Set<StorageAttachedIndex> indexes)
    {
        logger.debug(logMessage("Starting index build on {}"), sstable.descriptor);

        CountDownLatch perSSTableFileLock = null;
        StorageAttachedIndexWriter indexWriter = null;

        Ref<? extends SSTableReader> ref = sstable.tryRef();
        if (ref == null)
        {
            logger.warn(logMessage("Couldn't acquire reference to the SSTable {}. It may have been removed."), sstable.descriptor);
            return false;
        }

        try (RandomAccessReader dataFile = sstable.openDataReader();
             LifecycleTransaction txn = LifecycleTransaction.offline(OperationType.INDEX_BUILD, sstable))
        {
            perSSTableFileLock = shouldWritePerSSTableFiles(sstable);
            // If we were unable to get the per-SSTable file lock it means that the
            // per-SSTable components are already being built, so we only want to
            // build the per-index components
            boolean perIndexComponentsOnly = perSSTableFileLock == null;
            // remove existing per column index files instead of overwriting
            IndexDescriptor indexDescriptor = IndexDescriptor.create(sstable);
            indexes.forEach(index -> indexDescriptor.deleteColumnIndex(index.termType(), index.identifier()));

            indexWriter = StorageAttachedIndexWriter.createBuilderWriter(indexDescriptor, indexes, txn, perIndexComponentsOnly);

            indexWriter.begin();

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. No action needed in most cases: the builder skips the SSTable and the build is retried against the live set; verify the index reaches a BUILD_SUCCESSFUL status via the system_views.system_storageattachedindexbuilds table.
  2. Check the logs for the descriptor name and confirm the SSTable was compacted away (look for compaction and release logs for the same descriptor).
  3. If the index is stuck incomplete, force a rebuild: `nodetool scsirebuild` / DROP and re-CREATE the index so all live SSTables are re-enqueued.
  4. Reduce racing lifecycle churn (pause heavy compaction or avoid DDL on the table) during explicit index rebuilds.

Example fix

// before: assuming the ref is always available
try (Ref<? extends SSTableReader> ref = sstable.tryRef()) { ... }
// after: the code already handles it; callers must tolerate false
boolean built = indexSSTable(sstable, ...);
if (!built) logger.info("SSTable {} skipped for index build (already removed)", sstable.descriptor);
Defensive patterns

Strategy: fallback

Validate before calling

// before triggering index build
if (!sstables.allMatch(s -> s.tryRef() != null)) {
    logger.info("Some SSTables no longer referenceable; build set will be adjusted");
}

Prevention

When it happens

Trigger: The compaction manager replaced/dropped the SSTable between the time the index build task was queued and when indexSSTable() executed; concurrent truncation (DROP TABLE / TRUNCATE) releases all SSTables while a secondary-index build is in flight; a manual `nodetool relocatesstables`/cleanup removed the reader.

Common situations: Running REBUILD of a storage-attached index on a busy table with heavy compaction; dropping or truncating a table while an index rebuild is queued after a node restart; repair-triggered compaction racing a newly-created index backfill.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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