apache/dubbo · error · RejectedExecutionException

The task queue does not have executor!

Error message

The task queue does not have executor!

What it means

Thrown by TaskQueue.offer() when the executor field is null. The TaskQueue is tightly coupled to EagerThreadPoolExecutor — its offer() logic (deciding whether to queue vs. create a new thread) needs to query the executor's pool size and active count. If setExecutor() was never called, the queue cannot function and rejects the offer. This indicates a misconfigured or incompletely constructed EagerThreadPool.

Source

Thrown at dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/support/eager/TaskQueue.java:47

 */
public class TaskQueue<R extends Runnable> extends LinkedBlockingQueue<Runnable> {

    private static final long serialVersionUID = -2635853580887179627L;

    private EagerThreadPoolExecutor executor;

    public TaskQueue(int capacity) {
        super(capacity);
    }

    public void setExecutor(EagerThreadPoolExecutor exec) {
        executor = exec;
    }

    @Override
    public boolean offer(Runnable runnable) {
        if (executor == null) {
            throw new RejectedExecutionException("The task queue does not have executor!");
        }

        int currentPoolThreadSize = executor.getPoolSize();
        // have free worker. put task into queue to let the worker deal with task.
        if (executor.getActiveCount() < currentPoolThreadSize) {
            return super.offer(runnable);
        }

        // return false to let executor create new worker.
        if (currentPoolThreadSize < executor.getMaximumPoolSize()) {
            return false;
        }

        // currentPoolThreadSize >= max
        return super.offer(runnable);
    }

    /**

View on GitHub (pinned to 3a3043227f)

Solutions

  1. Ensure setExecutor(eagerThreadPoolExecutor) is called on the TaskQueue before any task is submitted — the standard Dubbo EagerThreadPool factory does this automatically.
  2. Do not use TaskQueue with a plain ThreadPoolExecutor; it is designed exclusively for EagerThreadPoolExecutor.
  3. If constructing manually: TaskQueue<Runnable> queue = new TaskQueue<>(capacity); EagerThreadPoolExecutor exec = new EagerThreadPoolExecutor(..., queue, ...); queue.setExecutor(exec);
  4. Use Dubbo's built-in thread pool SPI (threadpool=eager) instead of manual construction.

Example fix

// before — TaskQueue without executor wiring
TaskQueue<Runnable> queue = new TaskQueue<>(256);
ThreadPoolExecutor pool = new ThreadPoolExecutor(4, 16, 60, SECONDS, queue, factory);
pool.execute(task); // throws: executor is null

// after — wire executor before use
TaskQueue<Runnable> queue = new TaskQueue<>(256);
EagerThreadPoolExecutor pool = new EagerThreadPoolExecutor(4, 16, 60, SECONDS, queue, factory, abortHandler);
queue.setExecutor(pool);
pool.execute(task);
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the executor is wired before use
public static TaskQueue<Runnable> createWiredQueue(int capacity, EagerThreadPoolExecutor exec) {
    TaskQueue<Runnable> queue = new TaskQueue<>(capacity);
    queue.setExecutor(exec);
    return queue;
}

// Verify before first execute:
if (queueHasExecutor(queue)) { // reflectively or via a wrapper that tracks state
    pool.execute(task);
}

Try / catch

try {
    pool.execute(task);
} catch (RejectedExecutionException e) {
    if (e.getMessage().contains("does not have executor")) {
        throw new IllegalStateException("TaskQueue not wired to its executor — call setExecutor()", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: A TaskQueue is constructed and used by a ThreadPoolExecutor (directly or via framework wiring) without calling setExecutor(executor) first. This happens if the TaskQueue is passed to a plain ThreadPoolExecutor instead of EagerThreadPoolExecutor, or if framework initialization code that wires the executor was bypassed.

Common situations: Custom thread pool construction that uses TaskQueue without calling setExecutor(); a bug in framework/SPI initialization; manually constructing an EagerThreadPoolExecutor where the setExecutor() call was omitted; upgrading Dubbo versions where the TaskQueue wiring contract changed.

Related errors


AI-assisted analysis of apache/dubbo@3a3043227f (2026-08-14). Data as JSON: /api/errors/ab70354550f90725. Report an issue: GitHub.