apache/cassandra · error · RejectedExecutionException

${executor} has shut down

Error message

${executor} has shut down

What it means

Thrown as a RejectedExecutionException by ThreadPoolExecutorBase when a task is submitted to an executor that has already been shut down. The submission loop first checks executor.isShutdown() and rejects rather than queueing into a dead pool.

Source

Thrown at src/java/org/apache/cassandra/concurrent/ThreadPoolExecutorBase.java:54

 * <li>Tasks rejected due to overflow of the queue block the submitting thread rather than throwing {@link RejectedExecutionException}
 * <li>{@link RunnableFuture} rejected due to executor shutdown will be cancelled
 * <li>{@link RunnableFuture} removed by {@link #shutdownNow()} will be cancelled
 *
 * We also provide a shutdown hook for JMX registration cleanup.
 */
public class ThreadPoolExecutorBase extends ThreadPoolExecutor implements ResizableThreadPool
{
    public static final RejectedExecutionHandler blockingExecutionHandler = (task, executor) ->
    {
        BlockingQueue<Runnable> queue = executor.getQueue();
        try
        {
            while (true)
            {
                try
                {
                    if (executor.isShutdown())
                        throw new RejectedExecutionException(executor + " has shut down");

                    if (queue.offer(task, 1, TimeUnit.SECONDS))
                        break;
                }
                catch (InterruptedException e)
                {
                    throw new UncheckedInterruptedException(e);
                }
            }
        }
        catch (Throwable t)
        {
            //Give some notification to the caller the task isn't going to run
            if (task instanceof java.util.concurrent.Future)
                ((java.util.concurrent.Future<?>) task).cancel(false);
            throw t;
        }
    };

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Stop producers before calling shutdown(), or add a terminated flag producers check before submitting
  2. Catch RejectedExecutionException around submit and treat it as 'dropped during shutdown'
  3. Use a longer-lived executor or delay shutdown until pending work completes
  4. Guard submissions with ExecutorService.isShutdown() checks at the call site

Example fix

// before
executor.submit(() -> handle(message));
// after
try
{
    executor.submit(() -> handle(message));
}
catch (RejectedExecutionException e)
{
    logger.debug("Executor shut down, dropping task", e);
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (executor.isShutdown()) { logger.warn("Executor shut down; skipping submit"); return; }

Try / catch

try {
    executor.submit(task);
} catch (RejectedExecutionException e) {
    logger.debug("Task dropped because executor shut down", e);
}

Prevention

When it happens

Trigger: Calling executor.execute()/submit() after shutdown() or shutdownNow() was invoked, typically during node shutdown, decommission, or stop of a service holding the executor.

Common situations: Background daemons or callbacks firing during Cassandra shutdown, tests tearing down clusters while async work is still submitting, race between a scheduler and lifecycle shutdown hooks.

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


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