{"record":{"id":"84b75f5563b6b7e7","repo":"eclipse-vertx/vert.x","slug":"server-already-bound","errorCode":null,"errorMessage":"Server already bound","messagePattern":"Server already bound","errorType":"validation","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"vertx-core/src/main/java/io/vertx/core/http/impl/quic/QuicHttpServer.java","lineNumber":72,"sourceCode":"  public QuicHttpServer(VertxInternal vertx, HttpServerConfig config, ServerSSLOptions sslOptions, HttpServerMetrics<?, ?> httpMetrics) {\n\n    // We own the copy\n    sslOptions.setApplicationLayerProtocols(Arrays.asList(Http3.supportedApplicationProtocols()));\n\n    this.vertx = vertx;\n    this.config = config;\n    this.sslOptions = sslOptions;\n    this.http3Config = config.getHttp3Config() != null ? config.getHttp3Config() : new Http3ServerConfig();\n    this.quicConfig = config.getQuicConfig() != null ? config.getQuicConfig() : new QuicServerConfig();\n    this.actualPort = 0;\n    this.httpMetrics = httpMetrics;\n    this.manageMetrics = httpMetrics == null;\n  }\n\n  @Override\n  public HttpServer requestHandler(Handler<HttpServerRequest> handler) {\n    if (actualPort > 0) {\n      throw new IllegalStateException(\"Server already bound\");\n    }\n    this.requestHandler = handler;\n    return this;\n  }\n\n  @Override\n  public Handler<HttpServerRequest> requestHandler() {\n    return requestHandler;\n  }\n\n  @Override\n  public HttpServer invalidRequestHandler(Handler<HttpServerRequest> handler) {\n    if (actualPort > 0) {\n      throw new IllegalStateException(\"Server already bound\");\n    }\n    return this;\n  }\n","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/eclipse-vertx/vert.x/blob/fb308bd8c3f12c79f4ae89bef67fadf6c80d036e/vertx-core/src/main/java/io/vertx/core/http/impl/quic/QuicHttpServer.java#L54-L90","documentation":"QuicHttpServer.requestHandler rejects handler changes once the server is bound (actualPort > 0). Setting a request handler after the server is listening is unsupported because handlers must be in place before connections arrive; Vert.x throws IllegalStateException to prevent silent misconfiguration.","triggerScenarios":"Calling server.requestHandler(h) after listen() completed and reported an actual port > 0; reconfiguring a bound server from a lifecycle callback.","commonSituations":"Deferred wiring of handlers until after startup; hot-reload logic that mutates a running server; order bugs where listen() is awaited before handler setup.","solutions":["Set requestHandler (and other handlers) before calling server.listen().","If the server is already bound, close() it, reconfigure, then listen() again.","Restructure startup so configuration is fully built before binding, e.g. build handlers first then a single listen call."],"exampleFix":"// before\nserver.listen(8443).onSuccess(s -> s.requestHandler(handler)); // too late\n// after\nserver.requestHandler(handler);\nserver.listen(8443);","handlingStrategy":"validation","validationCode":"if (server.actualPort() > 0) throw new IllegalStateException(\"set handlers before listen()\");","typeGuard":null,"tryCatchPattern":"try { server.requestHandler(h); } catch (IllegalStateException e) { server.close().onSuccess(v -> { server.requestHandler(h); server.listen(port); }); }","preventionTips":["Register all handlers before calling listen()","Enforce a single startup method that wires handlers then binds","Never mutate a running server's handlers","Use actualPort() to assert bind state in lifecycle code"],"tags":["quic","http-server","lifecycle","illegal-state"],"backgroundTag":"invalid-state-transition","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"}