apache/cassandra · error · IllegalStateException
Failed setting repairedAt to %d on %s (repairedAt is %d)
Error message
Failed setting repairedAt to %d on %s (repairedAt is %d)
What it means
The repairedAt branch of verifyMetadata: after CompactionStrategyManager writes a repairedAt timestamp to an sstable (mutateRepaired path used by full/incremental repair and anticompaction), the method re-reads sstable.getRepairedAt() and throws IllegalStateException if it differs from the requested value. It indicates the repair-metadata update did not stick, usually due to a concurrent mutation on the same sstable.
Source
Thrown at src/java/org/apache/cassandra/db/compaction/CompactionStrategyManager.java:1535
try
{
// if there was an exception mutating repairedAt, we should still notify for the
// sstables that we were able to modify successfully before releasing the lock
cfs.getTracker().notifySSTableRepairedStatusChanged(changed);
}
finally
{
writeLock.unlock();
}
}
}
private static void verifyMetadata(SSTableReader sstable, long repairedAt, TimeUUID pendingRepair, boolean isTransient)
{
if (!Objects.equals(pendingRepair, sstable.getPendingRepair()))
throw new IllegalStateException(String.format("Failed setting pending repair to %s on %s (pending repair is %s)", pendingRepair, sstable, sstable.getPendingRepair()));
if (repairedAt != sstable.getRepairedAt())
throw new IllegalStateException(String.format("Failed setting repairedAt to %d on %s (repairedAt is %d)", repairedAt, sstable, sstable.getRepairedAt()));
if (isTransient != sstable.isTransient())
throw new IllegalStateException(String.format("Failed setting isTransient to %b on %s (isTransient is %b)", isTransient, sstable, sstable.isTransient()));
}
public CleanupSummary releaseRepairData(Collection<TimeUUID> sessions)
{
List<CleanupTask> cleanupTasks = new ArrayList<>();
readLock.lock();
try
{
for (PendingRepairManager prm : Iterables.concat(pendingRepairs.getManagers(), transientRepairs.getManagers()))
cleanupTasks.add(prm.releaseSessionData(sessions));
}
finally
{
readLock.unlock();
}
View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Re-run repair for the affected ranges so the repairedAt timestamp is recomputed and rewritten
- Retry after concurrent repair/compaction activity completes
- Serialize repair operations on a table (avoid overlapping incremental repairs)
- If it occurs with no concurrent activity, file a Cassandra bug with sstablemetadata output
Defensive patterns
Strategy: try-catch
Validate before calling
long current = sstable.getRepairedAt();
if (current != expectedOldValue)
logger.warn("repairedAt already changed to {} on {}", current, sstable); // skip redundant mutation Try / catch
try { mutateAndVerify(sstable, repairedAt); }
catch (IllegalStateException e) {
// treat as benign race; repair will re-attempt, or re-run repair for the range
} Prevention
- Avoid concurrent repair sessions on the same table
- Check getRepairedAt() before writing to skip no-op mutations
- Run repair finalization single-threaded per sstable
- Re-run repair if repairedAt discrepancies appear in logs
When it happens
Trigger: Setting repairedAt during incremental repair session promotion (UNREPAIRED_SSTABLE -> timestamp) or when transitioning transient->repaired, followed by verification against the live metadata which reflects a different value because another writer mutated repairedAt in between.
Common situations: Two repair sessions finalizing over the same sstable; repair finalization racing with compaction or cleanup that resets repaired state; upgrade-time sstable metadata rewrite conflicts.
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
- Failed setting pending repair to %s on %s (pending repair is
- Failed setting isTransient to %b on %s (isTransient is %b)
- No holder claimed isPendingRepair: %s, isPendingRepair %s
- Could not reference sstables
- Maximum pool size has been changed while resizing
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/1da979f0c9ec524c.
Report an issue: GitHub.