{"record":{"id":"ab70354550f90725","repo":"apache/dubbo","slug":"the-task-queue-does-not-have-executor","errorCode":null,"errorMessage":"The task queue does not have executor!","messagePattern":"The task queue does not have executor!","errorType":"exception","errorClass":"RejectedExecutionException","httpStatus":null,"severity":"error","filePath":"dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/support/eager/TaskQueue.java","lineNumber":47,"sourceCode":" */\npublic class TaskQueue<R extends Runnable> extends LinkedBlockingQueue<Runnable> {\n\n    private static final long serialVersionUID = -2635853580887179627L;\n\n    private EagerThreadPoolExecutor executor;\n\n    public TaskQueue(int capacity) {\n        super(capacity);\n    }\n\n    public void setExecutor(EagerThreadPoolExecutor exec) {\n        executor = exec;\n    }\n\n    @Override\n    public boolean offer(Runnable runnable) {\n        if (executor == null) {\n            throw new RejectedExecutionException(\"The task queue does not have executor!\");\n        }\n\n        int currentPoolThreadSize = executor.getPoolSize();\n        // have free worker. put task into queue to let the worker deal with task.\n        if (executor.getActiveCount() < currentPoolThreadSize) {\n            return super.offer(runnable);\n        }\n\n        // return false to let executor create new worker.\n        if (currentPoolThreadSize < executor.getMaximumPoolSize()) {\n            return false;\n        }\n\n        // currentPoolThreadSize >= max\n        return super.offer(runnable);\n    }\n\n    /**","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/apache/dubbo/blob/3a3043227f5571d25eb2889de5bca22f2914843b/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/support/eager/TaskQueue.java#L29-L65","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure setExecutor(eagerThreadPoolExecutor) is called on the TaskQueue before any task is submitted — the standard Dubbo EagerThreadPool factory does this automatically.","Do not use TaskQueue with a plain ThreadPoolExecutor; it is designed exclusively for EagerThreadPoolExecutor.","If constructing manually: TaskQueue<Runnable> queue = new TaskQueue<>(capacity); EagerThreadPoolExecutor exec = new EagerThreadPoolExecutor(..., queue, ...); queue.setExecutor(exec);","Use Dubbo's built-in thread pool SPI (threadpool=eager) instead of manual construction."],"exampleFix":"// before — TaskQueue without executor wiring\nTaskQueue<Runnable> queue = new TaskQueue<>(256);\nThreadPoolExecutor pool = new ThreadPoolExecutor(4, 16, 60, SECONDS, queue, factory);\npool.execute(task); // throws: executor is null\n\n// after — wire executor before use\nTaskQueue<Runnable> queue = new TaskQueue<>(256);\nEagerThreadPoolExecutor pool = new EagerThreadPoolExecutor(4, 16, 60, SECONDS, queue, factory, abortHandler);\nqueue.setExecutor(pool);\npool.execute(task);","handlingStrategy":"validation","validationCode":"// Ensure the executor is wired before use\npublic static TaskQueue<Runnable> createWiredQueue(int capacity, EagerThreadPoolExecutor exec) {\n    TaskQueue<Runnable> queue = new TaskQueue<>(capacity);\n    queue.setExecutor(exec);\n    return queue;\n}\n\n// Verify before first execute:\nif (queueHasExecutor(queue)) { // reflectively or via a wrapper that tracks state\n    pool.execute(task);\n}","typeGuard":null,"tryCatchPattern":"try {\n    pool.execute(task);\n} catch (RejectedExecutionException e) {\n    if (e.getMessage().contains(\"does not have executor\")) {\n        throw new IllegalStateException(\"TaskQueue not wired to its executor — call setExecutor()\", e);\n    }\n    throw e;\n}","preventionTips":["Always call queue.setExecutor(executor) immediately after constructing both objects.","Prefer Dubbo's built-in threadpool=eager SPI which handles wiring automatically.","Never pass a TaskQueue to a plain ThreadPoolExecutor — it is EagerThreadPoolExecutor-specific.","Write a factory method that constructs and wires both objects atomically."],"tags":["thread-pool","eager","configuration","initialization"],"backgroundTag":null,"analyzedSha":"3a3043227f5571d25eb2889de5bca22f2914843b","analyzedAt":"2026-08-14T00:43:19.853Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}