apache/shenyu · warning · NullPointerException
timer task null
Error message
timer task null
What it means
HierarchicalWheelTimer.add() explicitly throws NullPointerException('timer task null') when passed a null TimerTask. The hierarchical timing wheel cannot schedule an absent task, so the API fails fast before acquiring the read lock and starting the wheel.
Solutions
- Ensure the TimerTask is constructed before calling add(); check why the producing code returned null.
- Guard the call site with a null check and skip/log instead of scheduling.
- Use Objects.requireNonNull earlier in your own code to surface the origin of the null.
- If tasks are conditional, build an Optional<TimerTask> and only add when present.
Example fix
// before
TimerTask task = maybeBuildTask();
wheelTimer.add(task); // NPE if null
// after
TimerTask task = maybeBuildTask();
if (task != null) {
wheelTimer.add(task);
} Defensive patterns
Strategy: type-guard
Validate before calling
if (task == null) {
LOG.warn("skipping null timer task");
return;
} Type guard
void safeAdd(HierarchicalWheelTimer t, TimerTask task) {
if (t != null && task != null) {
t.add(task);
}
} Try / catch
try {
wheelTimer.add(task);
} catch (NullPointerException e) {
LOG.error("Attempted to schedule null timer task", e);
} Prevention
- Make task factories return Optional<TimerTask> or non-null defaults instead of null.
- Call Objects.requireNonNull at task construction to fail near the source.
- Review scheduling call sites after refactors for null-producing lookups.
When it happens
Trigger: Calling add(timerTask) with a null reference — typically a factory/builder returning null, an optional task computed as null, or a map lookup producing null before scheduling.
Common situations: Conditional task creation where the null branch is passed through unguarded; refactors where getDelayMs-based task wrappers are built lazily and can be null; tests passing null to probe behavior.
Related errors
- get join name is null
- McpAsyncServerExchange is required in McpSyncServerExchange
- Timer already shutdown
- ToolContext is required
AI-assisted analysis of apache/shenyu@567142e072 (2026-09-12).
Data as JSON: /api/errors/8f049888ca388976.
Report an issue: GitHub.
Appendix: source
Thrown at shenyu-common/src/main/java/org/apache/shenyu/common/timer/HierarchicalWheelTimer.java:93
* @param tickMs the tick ms
* @param wheelSize the wheel size
* @param startMs the start ms
*/
public HierarchicalWheelTimer(final String executorName,
final Long tickMs,
final Integer wheelSize,
final Long startMs) {
ThreadFactory threadFactory = ShenyuThreadFactory.create(executorName, false);
taskExecutor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(), threadFactory);
workerThread = threadFactory.newThread(new Worker(this));
timingWheel = new TimingWheel(tickMs, wheelSize, startMs, taskCounter, delayQueue);
}
@Override
public void add(final TimerTask timerTask) {
if (Objects.isNull(timerTask)) {
throw new NullPointerException("timer task null");
}
this.readLock.lock();
try {
start();
long millis = TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
this.addTimerTaskEntry(new TimerTaskList.TimerTaskEntry(this, timerTask, timerTask.getDelayMs() + millis));
} finally {
this.readLock.unlock();
}
}
private void addTimerTaskEntry(final TimerTaskList.TimerTaskEntry timerTaskEntry) {
if (!timingWheel.add(timerTaskEntry)) {
if (!timerTaskEntry.cancelled()) {
taskExecutor.submit(() -> timerTaskEntry.getTimerTask().run(timerTaskEntry));
}
}View on GitHub (pinned to 567142e072)