apache/dubbo · error · IllegalArgumentException

tickDuration must be greater than 0

Error message

tickDuration must be greater than 0: {}

What it means

IllegalArgumentException thrown by the HashedWheelTimer constructor when tickDuration is <= 0. The tick duration defines the interval between wheel ticks (the timer's resolution). A non-positive tick duration is nonsensical — the timer could never advance. The constructor validates this before allocating the wheel structure. Note this checks the raw input value before unit conversion to nanos.

Solutions

  1. Set tickDuration to a positive value — 100 (milliseconds) is the Dubbo/Netty default and is appropriate for most I/O timeout use cases.
  2. Validate the configured/computed tickDuration before construction and fall back to a sensible default.
  3. Check for unit mismatches that cause the value to collapse to 0 (e.g., passing nanoseconds where milliseconds are expected).

Example fix

// before
long tick = config.getTickDuration(); // 0 if unset
new HashedWheelTimer(factory, tick, TimeUnit.MILLISECONDS, 512);

// after
long tick = config.getTickDuration();
if (tick <= 0) tick = 100; // default to 100ms
new HashedWheelTimer(factory, tick, TimeUnit.MILLISECONDS, 512);
Defensive patterns

Strategy: validation

Validate before calling

if (tickDuration <= 0) {
    throw new IllegalArgumentException("tickDuration must be positive, got: " + tickDuration);
}
// or default:
long safeTick = tickDuration > 0 ? tickDuration : 100L; // 100ms default
new HashedWheelTimer(factory, safeTick, unit, ticksPerWheel);

Prevention

When it happens

Trigger: Passing a tickDuration of 0 or a negative number to the HashedWheelTimer constructor. This can happen when the value is read from configuration that defaulted to 0, or computed from a formula that yields zero/negative.

Common situations: Configuration property (e.g., a timeout or tick interval) set to 0 or left unset defaulting to 0; computed duration that evaluates to zero due to integer division or unit mismatch; test code passing 0 as a placeholder.

Related errors


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

Appendix: source

Thrown at dubbo-common/src/main/java/org/apache/dubbo/common/timer/HashedWheelTimer.java:238

     *                           {@link java.util.concurrent.RejectedExecutionException}
     *                           being thrown. No maximum pending timeouts limit is assumed if
     *                           this value is 0 or negative.
     * @throws NullPointerException     if either of {@code threadFactory} and {@code unit} is {@code null}
     * @throws IllegalArgumentException if either of {@code tickDuration} and {@code ticksPerWheel} is &lt;= 0
     */
    public HashedWheelTimer(
        ThreadFactory threadFactory,
        long tickDuration, TimeUnit unit, int ticksPerWheel,
        long maxPendingTimeouts) {

        if (threadFactory == null) {
            throw new NullPointerException("threadFactory");
        }
        if (unit == null) {
            throw new NullPointerException("unit");
        }
        if (tickDuration <= 0) {
            throw new IllegalArgumentException("tickDuration must be greater than 0: " + tickDuration);
        }
        if (ticksPerWheel <= 0) {
            throw new IllegalArgumentException("ticksPerWheel must be greater than 0: " + ticksPerWheel);
        }

        // Normalize ticksPerWheel to power of two and initialize the wheel.
        wheel = createWheel(ticksPerWheel);
        mask = wheel.length - 1;

        // Convert tickDuration to nanos.
        this.tickDuration = unit.toNanos(tickDuration);

        // Prevent overflow.
        if (this.tickDuration >= Long.MAX_VALUE / wheel.length) {
            throw new IllegalArgumentException(String.format(
                "tickDuration: %d (expected: 0 < tickDuration in nanos < %d",
                tickDuration, Long.MAX_VALUE / wheel.length));
        }

View on GitHub (pinned to 3a3043227f)