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
- 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.
- Check the logs for the descriptor name and confirm the SSTable was compacted away (look for compaction and release logs for the same descriptor).
- If the index is stuck incomplete, force a rebuild: `nodetool scsirebuild` / DROP and re-CREATE the index so all live SSTables are re-enqueued.
- 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
- Avoid DDL (TRUNCATE/DROP) and heavy compaction while running explicit index rebuilds.
- Treat a `false` return from indexSSTable as a normal skip, not a failure.
- Monitor index build status tables to confirm the skipped SSTable set gets rebuilt.
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
- Could not reference sstables
- Missing SAI index to import for SSTable %s on %s.%s
- Missing SAI index to import for index %s on %s.%s
- No holder claimed
- You can't mix repaired and unrepaired data in a compaction
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/9cb58188be331247.
Report an issue: GitHub.