apache/cassandra · error · IllegalStateException
Maximum pool size has been changed while resizing
Error message
Maximum pool size has been changed while resizing
What it means
setMaximumPoolSize resizes the worker-permit pool with a compareAndSet on the current maximum; if another thread changed maximumPoolSize between the read and the CAS, the resize is abandoned and an IllegalStateException is thrown rather than silently overwriting the concurrent update. It is a lost-update detection mechanism for concurrent resizes.
Source
Thrown at src/java/org/apache/cassandra/concurrent/SEPExecutor.java:381
public int getMaximumPoolSize()
{
return maximumPoolSize.get();
}
@Override
public synchronized void setMaximumPoolSize(int newMaximumPoolSize)
{
final int oldMaximumPoolSize = maximumPoolSize.get();
if (newMaximumPoolSize < 0)
{
throw new IllegalArgumentException("Maximum number of workers must not be negative");
}
int deltaWorkPermits = newMaximumPoolSize - oldMaximumPoolSize;
if (!maximumPoolSize.compareAndSet(oldMaximumPoolSize, newMaximumPoolSize))
{
throw new IllegalStateException("Maximum pool size has been changed while resizing");
}
if (deltaWorkPermits == 0)
return;
permits.updateAndGet(cur -> updateWorkPermits(cur, workPermits(cur) + deltaWorkPermits));
logger.info("Resized {} maximum pool size from {} to {}", name, oldMaximumPoolSize, newMaximumPoolSize);
// If we we have more work permits than before we should spin up a worker now rather than waiting
// until either a new task is enqueued (if all workers are descheduled) or a spinning worker calls
// maybeSchedule().
pool.maybeStartSpinningWorker();
maximumPoolSizeListener.onUpdateMaximumPoolSize(newMaximumPoolSize);
}
private static int taskPermits(long both)
{View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Retry the resize: re-read the new maximumPoolSize (getMaximumPoolSize) and call setMaximumPoolSize again until it succeeds
- Serialize resizes: perform all setMaximumPoolSize calls from a single thread or under a shared lock
- Check whether multiple components (JMX + config applier) are resizing the same executor and let only one own it
- Catch IllegalStateException around the call and retry with backoff if concurrent resizes are expected
Example fix
// before
executor.setMaximumPoolSize(newSize); // IllegalStateException on race
// after
boolean resized = false;
while (!resized)
{
try { executor.setMaximumPoolSize(newSize); resized = true; }
catch (IllegalStateException e) { Thread.yield(); }
} Defensive patterns
Strategy: retry
Validate before calling
// detect concurrent resizers before attempting
if (resizeInProgress.compareAndSet(false, true))
try { executor.setMaximumPoolSize(newSize); } finally { resizeInProgress.set(false); } Try / catch
try
{
executor.setMaximumPoolSize(newSize);
}
catch (IllegalStateException e)
{
// someone else resized concurrently; re-read and retry
newSize = executor.getMaximumPoolSize();
} Prevention
- Serialize all pool resizes through a single owner (thread or lock)
- Avoid overlapping JMX and automated resizes on the same executor
- Re-read getMaximumPoolSize() before each retry
- Add jitter/backoff when retrying contended resizes
When it happens
Trigger: Two threads (e.g. two JMX calls, an admin tool and a background resizer) calling setMaximumPoolSize on the same SEPExecutor concurrently; a retry loop that re-reads stale size and collides with another resize in flight.
Common situations: Operational tooling resizing pools concurrently during load; automated tuners racing with manual JMX changes; test code resizing pools from multiple threads.
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
- UnsupportedOperationException
- Queue is empty
- Cannot resize core pool size of SEPExecutor
- Maximum number of workers must not be negative
- ScheduledThreadPoolExecutor has shut down.
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/5ab333c73fb15370.
Report an issue: GitHub.