{"record":{"id":"6298ca43caff56e7","repo":"apache/dubbo","slug":"number-of-pending-timeouts-is-greater-than-or","errorCode":null,"errorMessage":"Number of pending timeouts ({}) is greater than or equal to maximum allowed pending timeouts ({})","messagePattern":"Number of pending timeouts \\((.+?)\\) is greater than or equal to maximum allowed pending timeouts \\((.+?)\\)","errorType":"exception","errorClass":"RejectedExecutionException","httpStatus":null,"severity":"warning","filePath":"dubbo-common/src/main/java/org/apache/dubbo/common/timer/HashedWheelTimer.java","lineNumber":396,"sourceCode":"    @Override\n    public boolean isStop() {\n        return WORKER_STATE_SHUTDOWN == WORKER_STATE_UPDATER.get(this);\n    }\n\n    @Override\n    public Timeout newTimeout(TimerTask task, long delay, TimeUnit unit) {\n        if (task == null) {\n            throw new NullPointerException(\"task\");\n        }\n        if (unit == null) {\n            throw new NullPointerException(\"unit\");\n        }\n\n        long pendingTimeoutsCount = pendingTimeouts.incrementAndGet();\n\n        if (maxPendingTimeouts > 0 && pendingTimeoutsCount > maxPendingTimeouts) {\n            pendingTimeouts.decrementAndGet();\n            throw new RejectedExecutionException(\"Number of pending timeouts (\"\n                + pendingTimeoutsCount + \") is greater than or equal to maximum allowed pending \"\n                + \"timeouts (\" + maxPendingTimeouts + \")\");\n        }\n\n        start();\n\n        // Add the timeout to the timeout queue which will be processed on the next tick.\n        // During processing all the queued HashedWheelTimeouts will be added to the correct HashedWheelBucket.\n        long deadline = System.nanoTime() + unit.toNanos(delay) - startTime;\n\n        // Guard against overflow.\n        if (delay > 0 && deadline < 0) {\n            deadline = Long.MAX_VALUE;\n        }\n        HashedWheelTimeout timeout = new HashedWheelTimeout(this, task, deadline);\n        timeouts.add(timeout);\n        return timeout;\n    }","sourceCodeStart":378,"sourceCodeEnd":414,"githubUrl":"https://github.com/apache/dubbo/blob/3a3043227f5571d25eb2889de5bca22f2914843b/dubbo-common/src/main/java/org/apache/dubbo/common/timer/HashedWheelTimer.java#L378-L414","documentation":"RejectedExecutionException thrown by HashedWheelTimer.newTimeout() when the number of pending (not-yet-fired) timeouts exceeds the configured maxPendingTimeouts limit. The pending timeout counter is incremented atomically before the check; if it exceeds the cap, it is decremented back and the exception is thrown. This is a backpressure mechanism to prevent unbounded memory growth from excessive scheduled timeouts. Only enforced when maxPendingTimeouts > 0 (0 or negative means unlimited).","triggerScenarios":"Scheduling timeouts faster than they fire, accumulating pending timeouts beyond the maxPendingTimeouts limit configured at construction. This indicates the timer is being overwhelmed — tasks are scheduled but not completing (either very long delays or the worker thread is stalled).","commonSituations":"High-throughput scheduling of short-lived timeouts where the fire rate can't keep up; long delay values causing accumulation; worker thread blocked or slow; misconfigured maxPendingTimeouts that is too low for the workload; a leak where timeouts are scheduled but never cancelled/fired.","solutions":["Increase maxPendingTimeouts if the workload legitimately requires many concurrent pending timeouts.","Reduce the rate of newTimeout calls or ensure timeouts fire promptly — investigate whether the worker thread is blocked.","Cancel timeouts that are no longer needed (Timeout.cancel()) to free pending slots.","If maxPendingTimeouts is unset (0/negative), the limit is disabled — set it to a value matching your expected concurrency as a safety net."],"exampleFix":"// before — unlimited pending timeouts causes memory risk, or limit too low\nnew HashedWheelTimer(factory, 100, TimeUnit.MILLISECONDS, 512, 100);\n// scheduling 101+ tasks throws\n\n// after — set a higher limit matching expected load\nnew HashedWheelTimer(factory, 100, TimeUnit.MILLISECONDS, 512, 100000);\n// or disable limit entirely (0 or negative)\nnew HashedWheelTimer(factory, 100, TimeUnit.MILLISECONDS, 512, 0);","handlingStrategy":"try-catch","validationCode":"// Check pending count before scheduling (requires access to pendingTimeouts())\nif (timer.pendingTimeouts() < maxPending) {\n    timer.newTimeout(task, delay, unit);\n} else {\n    applyBackpressure(); // throttle, queue, or reject at application level\n}","typeGuard":null,"tryCatchPattern":"try {\n    timer.newTimeout(task, delay, unit);\n} catch (RejectedExecutionException e) {\n    if (e.getMessage().contains(\"pending timeouts\")) {\n        logger.warn(\"Timer pending timeout limit reached, backing off\", e);\n        backoffAndRetry(task, delay, unit); // exponential backoff\n    } else {\n        throw e;\n    }\n}","preventionTips":["Set maxPendingTimeouts to a value matching expected concurrency, or 0 to disable the limit.","Cancel timeouts (Timeout.cancel()) when they are no longer needed to free pending slots.","Monitor timer.pendingTimeouts() and alert if it trends upward (indicates tasks not firing).","Ensure the worker thread is not blocked — a stalled worker causes pending timeouts to accumulate."],"tags":["timer","backpressure","capacity","memory"],"backgroundTag":null,"analyzedSha":"3a3043227f5571d25eb2889de5bca22f2914843b","analyzedAt":"2026-08-14T00:43:19.853Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}