{"record":{"id":"fe2585182eee9301","repo":"eclipse-vertx/vert.x","slug":"timeout-must-be-0-fe2585","errorCode":null,"errorMessage":"Timeout must be >= 0","messagePattern":"Timeout must be >= 0","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"vertx-core/src/main/java/io/vertx/core/net/impl/VertxConnection.java","lineNumber":186,"sourceCode":"    return shutdown(0L, TimeUnit.SECONDS);\n  }\n\n  /**\n   * Calls {@link #shutdown(Duration)}\n   */\n  public final Future<Void> shutdown(long timeout, TimeUnit unit) {\n    return shutdown(Duration.of(timeout, unit.toChronoUnit()));\n  }\n\n  /**\n   * Initiate the connection shutdown sequence.\n   *\n   * @param timeout the shutdown timeout\n   * @return the future completed after the channel's closure\n   */\n  public final Future<Void> shutdown(Duration timeout) {\n    if (timeout.isNegative()) {\n      throw new IllegalArgumentException(\"Timeout must be >= 0\");\n    }\n    ChannelPromise promise = channel.newPromise();\n    EventExecutor exec = chctx.executor();\n    if (exec.inEventLoop()) {\n      shutdown(timeout, promise);\n    } else {\n      exec.execute(() -> shutdown(timeout, promise));\n    }\n    PromiseInternal<Void> p = context.promise();\n    promise.addListener(p);\n    return p.future();\n  }\n\n  private void shutdown(Duration timeout, ChannelPromise promise) {\n    if (shutdown != null) {\n      ScheduledFuture<?> t = shutdownTimeout;\n      if (timeout.isZero() && (t == null || t.cancel(false))) {\n        shutdown = promise;","sourceCodeStart":168,"sourceCodeEnd":204,"githubUrl":"https://github.com/eclipse-vertx/vert.x/blob/fb308bd8c3f12c79f4ae89bef67fadf6c80d036e/vertx-core/src/main/java/io/vertx/core/net/impl/VertxConnection.java#L168-L204","documentation":"VertxConnection.shutdown(Duration) rejects negative durations with IllegalArgumentException ('Timeout must be >= 0'). The shutdown timeout bounds how long to wait for graceful close before force-closing the connection. Zero is allowed for immediate shutdown.","triggerScenarios":"Calling connection.shutdown(Duration.ofMillis(-1)) or shutdown(someDuration) where the duration was computed as negative (e.g. deadline.minus(now) after the deadline passed).","commonSituations":"Passing a user config of -1 intending 'infinite', or computing remaining time as endTime - currentTime when already expired.","solutions":["Clamp: shutdown(Duration.ofSeconds(Math.max(0, seconds)))","Handle expired deadlines explicitly by passing Duration.ZERO","Fix config semantics so 'disabled' maps to a valid large duration, not a negative one"],"exampleFix":"// before\nDuration remaining = deadline.minus(Instant.now());\nconn.shutdown(remaining);\n// after\nDuration remaining = deadline.minus(Instant.now());\nconn.shutdown(remaining.isNegative() ? Duration.ZERO : remaining);","handlingStrategy":"validation","validationCode":"if (timeout != null && timeout.isNegative()) timeout = Duration.ZERO;","typeGuard":null,"tryCatchPattern":"try {\n  conn.shutdown(timeout);\n} catch (IllegalArgumentException e) {\n  conn.shutdown(Duration.ZERO);\n}","preventionTips":["Use .isNegative() before passing computed durations","Map 'infinite/disabled' config values to a large positive duration","Use Duration.ZERO for expired deadlines"],"tags":["timeout","validation","connection"],"backgroundTag":"argument-out-of-range","analyzedSha":"fb308bd8c3f12c79f4ae89bef67fadf6c80d036e","analyzedAt":"2026-09-06T11:37:12.241Z","contentChangedAt":"2026-09-06T11:37:12.241Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}