{"record":{"id":"37187c4ce4269414","repo":"eclipse-vertx/vert.x","slug":"timeout-must-be-0","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/http/impl/http3/Http3Connection.java","lineNumber":269,"sourceCode":"            vSetting = Http3Settings.MAX_FIELD_SECTION_SIZE;\n            break;\n          default:\n            continue;\n        }\n        vSettings.setLong(vSetting, setting.getValue());\n      }\n    }\n    remoteSettings = vSettings;\n    Handler<HttpSettings> handler = remoteSettingsHandler;\n    if (handler != null) {\n      context.dispatch(vSettings, handler);\n    }\n  }\n\n  @Override\n  public Future<Void> shutdown(Duration timeout) {\n    if (timeout.isNegative()) {\n      throw new IllegalArgumentException(\"Timeout must be >= 0\");\n    }\n    return connection.shutdown(timeout);\n  }\n\n  private void handleShutdown(QuicStreamChannel localControlStream, Duration timeout) {\n    localGoAway = mostRecentRemoteStreamId + 4;\n    PromiseInternal<Void> p = context.promise();\n    if (remoteGoAway == -1L) {\n      Handler<Void> handler = shutdownHandler;\n      if (handler != null) {\n        context.emit(null, handler);\n      }\n    }\n    sendGoAway(localControlStream, mostRecentRemoteStreamId + 4, p);\n  }\n\n  private void handleGrace(QuicStreamChannel localControlStream) {\n    if (localGoAway == -1L || localGoAway > 0L) {","sourceCodeStart":251,"sourceCodeEnd":287,"githubUrl":"https://github.com/eclipse-vertx/vert.x/blob/fb308bd8c3f12c79f4ae89bef67fadf6c80d036e/vertx-core/src/main/java/io/vertx/core/http/impl/http3/Http3Connection.java#L251-L287","documentation":"Http3Connection.shutdown(Duration) validates that the shutdown timeout is not negative before delegating to the QUIC connection shutdown. A negative Duration is meaningless for a timeout, so IllegalArgumentException is thrown immediately.","triggerScenarios":"Calling shutdown(Duration.ofSeconds(-1)) or any negative duration, e.g. from misparsed configuration ('-1' meaning infinite) or an arithmetic result that went negative.","commonSituations":"Using -1 as an 'infinite/disabled' sentinel from other frameworks' conventions; subtracting deadlines producing negative Durations; config placeholders not replaced (e.g. ${timeout} parsed badly).","solutions":["Pass a zero or positive Duration, e.g. Duration.ZERO or Duration.ofSeconds(30).","Clamp: Duration t = timeout.isNegative() ? Duration.ZERO : timeout.","Use a null or a dedicated method if the API offers one for indefinite shutdown, instead of a negative sentinel."],"exampleFix":"// before\nconn.shutdown(Duration.ofSeconds(-1));\n// after\nconn.shutdown(Duration.ofSeconds(30));","handlingStrategy":"validation","validationCode":"if (timeout == null || timeout.isNegative()) throw new IllegalArgumentException(\"timeout must be >= 0\");","typeGuard":"boolean isValidShutdownTimeout(Duration d) { return d != null && !d.isNegative(); }","tryCatchPattern":"try { conn.shutdown(timeout); } catch (IllegalArgumentException e) { conn.shutdown(Duration.ofSeconds(30)); }","preventionTips":["Map '-1 means infinite' configs to Duration.ZERO or a large positive duration","Validate durations at config load time","Use java.time.Duration factories, not manual arithmetic","Check subtraction results for negative Durations"],"tags":["http3","quic","shutdown","duration"],"backgroundTag":"invalid-argument-value","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"}