apache/dubbo · error · NullPointerException

threadFactory

Error message

threadFactory

What it means

NullPointerException thrown by the HashedWheelTimer constructor when the threadFactory parameter is null. HashedWheelTimer spawns a dedicated worker thread for ticking, so it requires a ThreadFactory to create that thread. This is a fail-fast validation at construction time — the parameter is mandatory and cannot be defaulted. Dubbo's HashedWheelTimer is a Netty-derived timing-wheel implementation used for timeout scheduling.

Source

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

     *                           {@link TimerTask} execution.
     * @param tickDuration       the duration between tick
     * @param unit               the time unit of the {@code tickDuration}
     * @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);

View on GitHub (pinned to 3a3043227f)

Solutions

  1. Pass a non-null ThreadFactory — use Executors.defaultThreadFactory() if you have no custom requirement.
  2. If using dependency injection, verify the ThreadFactory bean is properly configured and not null.
  3. Add a null check before construction and supply a default factory.

Example fix

// before
ThreadFactory factory = possiblyNullFactory;
new HashedWheelTimer(factory, 100, TimeUnit.MILLISECONDS, 512);

// after
ThreadFactory factory = possiblyNullFactory != null ? possiblyNullFactory : Executors.defaultThreadFactory();
new HashedWheelTimer(factory, 100, TimeUnit.MILLISECONDS, 512);
Defensive patterns

Strategy: validation

Validate before calling

Objects.requireNonNull(threadFactory, "threadFactory must not be null");
// or supply a default:
ThreadFactory factory = threadFactory != null ? threadFactory : Executors.defaultThreadFactory();
new HashedWheelTimer(factory, tickDuration, unit, ticksPerWheel);

Prevention

When it happens

Trigger: Constructing a HashedWheelTimer with an explicit null threadFactory argument. Typically a programming error where the caller failed to supply or resolve the ThreadFactory before passing it.

Common situations: Custom code constructing HashedWheelTimer directly with a ThreadFactory variable that was never assigned; dependency injection misconfiguration that injects null for the ThreadFactory bean; conditional logic that yields null in an edge case.

Related errors


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