apache/dubbo · error · IllegalArgumentException
ticksPerWheel must be greater than 0: {}
Error message
ticksPerWheel must be greater than 0: {} What it means
IllegalArgumentException thrown by the HashedWheelTimer constructor when ticksPerWheel is <= 0. The wheel size (number of buckets) determines how timeouts are distributed across the hash wheel — it must be a positive integer. The constructor checks this at the top level before delegating to createWheel(). A non-positive wheel size makes hash-based scheduling impossible.
Source
Thrown at dubbo-common/src/main/java/org/apache/dubbo/common/timer/HashedWheelTimer.java:241
* @throws NullPointerException if either of {@code threadFactory} and {@code unit} is {@code null}
* @throws IllegalArgumentException if either of {@code tickDuration} and {@code ticksPerWheel} is <= 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));
}
workerThread = threadFactory.newThread(worker);
this.maxPendingTimeouts = maxPendingTimeouts;View on GitHub (pinned to 3a3043227f)
Solutions
- Set ticksPerWheel to a positive power of two (e.g., 512, the Dubbo/Netty default) — it is normalized internally but should be positive.
- Validate the value before construction and default to 512 if invalid.
- Use the convenience constructors that default ticksPerWheel to 512 (e.g., HashedWheelTimer(factory, tickDuration, unit)).
Example fix
// before int wheelSize = config.getWheelSize(); // 0 if unset new HashedWheelTimer(factory, 100, TimeUnit.MILLISECONDS, wheelSize); // after int wheelSize = config.getWheelSize(); if (wheelSize <= 0) wheelSize = 512; new HashedWheelTimer(factory, 100, TimeUnit.MILLISECONDS, wheelSize);
Defensive patterns
Strategy: validation
Validate before calling
if (ticksPerWheel <= 0) {
throw new IllegalArgumentException("ticksPerWheel must be positive, got: " + ticksPerWheel);
}
int safeWheel = ticksPerWheel > 0 ? ticksPerWheel : 512; // default
new HashedWheelTimer(factory, tickDuration, unit, safeWheel); Prevention
- Validate ticksPerWheel is a positive integer before construction.
- Default to 512 (the Dubbo/Netty standard) when configuration is absent or invalid.
- Prefer powers of two for wheel size (normalized internally anyway).
When it happens
Trigger: Passing a ticksPerWheel of 0 or negative to the HashedWheelTimer constructor. Common when the value comes from unvalidated configuration or an arithmetic expression that underflows.
Common situations: Configuration property for wheel size set to 0 or left unset; computed wheel size that evaluates to non-positive due to a formula error; passing 0 intentionally to mean 'default' without realizing it's invalid.
Related errors
- tickDuration must be greater than 0: {}
- threadFactory
- unit
- tickDuration: %d (expected: 0 < tickDuration in nanos < %d
- ticksPerWheel may not be greater than 2^30: {}
AI-assisted analysis of apache/dubbo@3a3043227f (2026-08-14).
Data as JSON: /api/errors/5ae13f65c1fc9656.
Report an issue: GitHub.