eclipse-vertx/vert.x · error · IllegalArgumentException

Invalid timer delay: ${delay}

Error message

Invalid timer delay: ${delay}

What it means

Thrown by ContextInternal.timer(long, TimeUnit) when a non-positive delay is passed. Vert.x requires timer delays to be strictly greater than zero, so scheduling a timer, periodic timer, or delayed action with delay <= 0 fails fast before any Netty scheduling happens.

Source

Thrown at vertx-core/src/main/java/io/vertx/core/internal/ContextInternal.java:428

   * Like {@link #timer(long, TimeUnit)} with a unit in millis.
   */
  default Timer timer(long delay) {
    return timer(delay, TimeUnit.MILLISECONDS);
  }

  /**
   * Create a timer task configured with the specified {@code delay}, when the timeout fires the timer future
   * is succeeded, when the timeout is cancelled the timer future is failed with a {@link java.util.concurrent.CancellationException}
   * instance.
   *
   * @param delay the delay
   * @param unit the delay unit
   * @return the timer object
   */
  default Timer timer(long delay, TimeUnit unit) {
    Objects.requireNonNull(unit);
    if (delay <= 0) {
      throw new IllegalArgumentException("Invalid timer delay: " + delay);
    }
    io.netty.util.concurrent.ScheduledFuture<Void> fut = nettyEventLoop().schedule(() -> null, delay, unit);
    TimerImpl timer = new TimerImpl(this, fut);
    fut.addListener(timer);
    return timer;
  }

  /**
   * @return {@code true} when the context is associated with a deployment
   */
  default boolean isDeployment() {
    return deployment() != null;
  }

  default int getInstanceCount() {
    DeploymentContext deployment = deployment();
    if (deployment == null) {
      return 0;

View on GitHub (pinned to fb308bd8c3)

Solutions

  1. Ensure the delay is > 0 before calling timer(), e.g. Math.max(1, delayMs)
  2. If the deadline already passed (delay <= 0), execute the timeout action immediately instead of scheduling
  3. Fix the config/default so the timeout value is a positive number

Example fix

// before
ctx.timer(timeoutMs, TimeUnit.MILLISECONDS);
// after
if (timeoutMs <= 0) {
  handleTimeoutNow();
} else {
  ctx.timer(timeoutMs, TimeUnit.MILLISECONDS);
}
Defensive patterns

Strategy: validation

Validate before calling

if (delay <= 0) throw new IllegalArgumentException("timer delay must be > 0, got " + delay);

Try / catch

try { t = ctx.timer(delay, unit); } catch (IllegalArgumentException e) { handleImmediateTimeout(); }

Prevention

When it happens

Trigger: Calling ctx.timer(0, TimeUnit.MILLISECONDS) or ctx.timer(-5, TimeUnit.SECONDS); passing an uncomputed/zero delay value to vertx.timer or APIs built on it (setTimer-like helpers, timeouts, debounce logic).

Common situations: A timeout constant initialized to 0 meaning 'no timeout' but passed to timer anyway; config value defaulted to 0; arithmetic producing a negative remaining-time (deadline already passed) fed into the timer.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of eclipse-vertx/vert.x@fb308bd8c3 (2026-09-06). Data as JSON: /api/errors/40efa1d67ef83c53. Report an issue: GitHub.