apache/dubbo · error · NullPointerException

task

Error message

task

What it means

NullPointerException thrown by HashedWheelTimer.newTimeout() when the task parameter is null. newTimeout() schedules a TimerTask to run after a delay; a null task has nothing to execute. The method fails fast before incrementing the pending timeout counter. This is standard precondition validation — task is mandatory.

Source

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

            if (interrupted) {
                Thread.currentThread().interrupt();
            }
        } finally {
            INSTANCE_COUNTER.decrementAndGet();
        }
        return worker.unprocessedTimeouts();
    }

    @Override
    public boolean isStop() {
        return WORKER_STATE_SHUTDOWN == WORKER_STATE_UPDATER.get(this);
    }

    @Override
    public Timeout newTimeout(TimerTask task, long delay, TimeUnit unit) {
        if (task == null) {
            throw new NullPointerException("task");
        }
        if (unit == null) {
            throw new NullPointerException("unit");
        }

        long pendingTimeoutsCount = pendingTimeouts.incrementAndGet();

        if (maxPendingTimeouts > 0 && pendingTimeoutsCount > maxPendingTimeouts) {
            pendingTimeouts.decrementAndGet();
            throw new RejectedExecutionException("Number of pending timeouts ("
                + pendingTimeoutsCount + ") is greater than or equal to maximum allowed pending "
                + "timeouts (" + maxPendingTimeouts + ")");
        }

        start();

        // Add the timeout to the timeout queue which will be processed on the next tick.
        // During processing all the queued HashedWheelTimeouts will be added to the correct HashedWheelBucket.

View on GitHub (pinned to 3a3043227f)

Solutions

  1. Ensure a non-null TimerTask is passed — instantiate the task before the newTimeout call.
  2. Add a null check before calling newTimeout and handle the null case appropriately (skip, log, or use a no-op task).

Example fix

// before
TimerTask task = taskRegistry.get(id); // may return null
timer.newTimeout(task, 5, TimeUnit.SECONDS);

// after
TimerTask task = taskRegistry.get(id);
if (task == null) {
    log.warn("No task found for id {}, skipping scheduling", id);
    return;
}
timer.newTimeout(task, 5, TimeUnit.SECONDS);
Defensive patterns

Strategy: validation

Validate before calling

Objects.requireNonNull(task, "task must not be null");
timer.newTimeout(task, delay, unit);

Prevention

When it happens

Trigger: Calling timer.newTimeout(null, delay, unit) — passing a null task. Typically a programming error where the task object was not resolved or a factory method returned null.

Common situations: Task reference that was never assigned; conditional logic that yields null in an edge case; deserialization or lookup that returns null for the task; calling newTimeout with a placeholder before the real task is available.

Related errors


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