apache/dubbo · error · NullPointerException

unit

Error message

unit

What it means

NullPointerException thrown by the HashedWheelTimer constructor when the unit (TimeUnit) parameter is null. The tick duration is meaningless without a unit, and the constructor converts tickDuration to nanoseconds via unit.toNanos(), so a null unit would cause an NPE later anyway. The constructor fails fast with a clear message instead. TimeUnit is mandatory for any time-based configuration.

Source

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

     * @param ticksPerWheel      the size of the wheel
     * @param maxPendingTimeouts The maximum number of pending timeouts after which call to
     *                           {@code newTimeout} will result in
     *                           {@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 <= 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(

View on GitHub (pinned to 3a3043227f)

Solutions

  1. Always pass an explicit TimeUnit constant (e.g., TimeUnit.MILLISECONDS) — never a potentially-null variable.
  2. If deriving from configuration, validate and default the parsed TimeUnit before passing it to the constructor.
  3. Use the convenience constructors (e.g., HashedWheelTimer(tickDuration, unit)) that reduce the number of mandatory parameters.

Example fix

// before
TimeUnit unit = parseUnit(config); // may return null
new HashedWheelTimer(factory, 100, unit, 512);

// after
TimeUnit unit = parseUnit(config);
if (unit == null) unit = TimeUnit.MILLISECONDS;
new HashedWheelTimer(factory, 100, unit, 512);
Defensive patterns

Strategy: validation

Validate before calling

Objects.requireNonNull(unit, "unit must not be null");
TimeUnit safeUnit = unit != null ? unit : TimeUnit.MILLISECONDS;
new HashedWheelTimer(threadFactory, tickDuration, safeUnit, ticksPerWheel);

Prevention

When it happens

Trigger: Constructing a HashedWheelTimer with a null TimeUnit argument for the tickDuration parameter. A straightforward programming error of passing null where a TimeUnit enum value is required.

Common situations: Calling code that derives the TimeUnit from configuration or a variable that resolved to null; misconfigured properties mapping that fails to parse a time unit string into a TimeUnit enum.

Related errors


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