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.

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)

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.