apache/cassandra · error · IllegalSSTableArgumentException

sstable is not pending repair

Error message

sstable is not pending repair

What it means

PendingRepairManager APIs (getOrCreate, getScanners) require a non-null pending repair ID because they manage only incremental-repair SSTables. checkPendingID throws IllegalSSTableArgumentException when a null ID is passed, indicating the caller passed an sstable that is not part of any pending repair.

Source

Thrown at src/java/org/apache/cassandra/db/compaction/PendingRepairManager.java:129

            {
                strategy = get(id);

                if (strategy == null)
                {
                    logger.debug("Creating {}.{} compaction strategy for pending repair: {}", cfs.metadata.keyspace, cfs.metadata.name, id);
                    strategy = cfs.createCompactionStrategyInstance(params);
                    strategies = mapBuilder().putAll(strategies).put(id, strategy).build();
                }
            }
        }
        return strategy;
    }

    private static void checkPendingID(TimeUUID pendingID)
    {
        if (pendingID == null)
        {
            throw new IllegalSSTableArgumentException("sstable is not pending repair");
        }
    }

    AbstractCompactionStrategy getOrCreate(SSTableReader sstable)
    {
        return getOrCreate(sstable.getSSTableMetadata().pendingRepair);
    }

    private synchronized void removeSessionIfEmpty(TimeUUID sessionID)
    {
        if (!strategies.containsKey(sessionID) || !strategies.get(sessionID).getSSTables().isEmpty())
            return;

        logger.debug("Removing compaction strategy for pending repair {} on  {}.{}", sessionID, cfs.metadata.keyspace, cfs.metadata.name);
        strategies = ImmutableMap.copyOf(Maps.filterKeys(strategies, k -> !k.equals(sessionID)));
    }

    synchronized void removeSSTable(SSTableReader sstable)

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Only pass SSTables with a non-null sstable.getSSTableMetadata().pendingRepair into PendingRepairManager
  2. Re-read sstable metadata to ensure the repair session has not completed and cleared the ID between selection and use
  3. Route non-repair SSTables to the normal compaction strategy instead
  4. If hit in stock Cassandra operation, capture nodetool tpstats/repair_admin output and file a bug

Example fix

// before
manager.getScanners(pendingRepairId, sstables);
// after
if (pendingRepairId == null) { regularStrategyScanners(sstables); } else { manager.getScanners(pendingRepairId, sstables); }
Defensive patterns

Strategy: type-guard

Validate before calling

if (sstable.getSSTableMetadata().pendingRepair == null)
    throw new IllegalArgumentException("sstable " + sstable + " is not pending repair; use regular compaction path");

Type guard

static boolean isPendingRepair(SSTableReader sstable) {
    return sstable.getSSTableMetadata().pendingRepair != null;
}

Try / catch

try {
    manager.getScanners(pendingId, sstables);
} catch (IllegalSSTableArgumentException e) {
    // fall back to the default compaction strategy scanners
    regularStrategy.getScanners(sstables, null);
}

Prevention

When it happens

Trigger: Calling PendingRepairManager.getOrCreate or getScanners with an sstable whose metadata pendingRepair is null (a regular, non-incremental-repair sstable).

Common situations: Custom compaction/repair tooling sending ordinary SSTables into the pending-repair path; race where a repair session finished and promoted/cleared the pendingRepair ID before the call; incremental repair misconfiguration.

Related errors


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