quarkusio/quarkus · critical · RuntimeException

failed to bind virtual http

Error message

failed to bind virtual http

What it means

Quarkus failed to start the internal virtual HTTP bootstrap server used by the Vert.x HTTP extension (e.g. dev-mode virtual hosting / management routing). The Netty bootstrap bind() to the VIRTUAL_HTTP socket threw, most often because the port is already in use or the network interface does not exist, and the wrapping RuntimeException hides the original cause (it is not passed as cause).

Source

Thrown at extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxHttpRecorder.java:1732

                        ch.pipeline().addLast("handler", handler);
                    }

                    private static HttpServerOptions createVirtualHttpServerOptions() {
                        var result = new HttpServerOptions();
                        Optional<MemorySize> maybeMaxHeadersSize = ConfigProvider.getConfig()
                                .getOptionalValue("quarkus.http.limits.max-header-size", MemorySize.class);
                        if (maybeMaxHeadersSize.isPresent()) {
                            result.setMaxHeaderSize(maybeMaxHeadersSize.get().asIntValue());
                        }
                        return result;
                    }
                });

        // Start the server.
        try {
            virtualBootstrapChannel = virtualBootstrap.bind(VIRTUAL_HTTP).sync();
        } catch (InterruptedException e) {
            throw new RuntimeException("failed to bind virtual http");
        }

    }

    public static Handler<HttpServerRequest> getRootHandler() {
        return ACTUAL_ROOT;
    }

    /**
     * used in the live reload handler to make sure the application has not been changed by another source (e.g. reactive
     * messaging)
     */
    public static Object getCurrentApplicationState() {
        return rootHandler;
    }

    private static boolean isGrpc(RoutingContext rc) {
        HttpServerRequest request = rc.request();

View on GitHub (pinned to e1c734241f)

Solutions

  1. Find and kill the process holding the virtual HTTP port (lsof -i :<port> / netstat -ano), often a leftover Quarkus dev process.
  2. Check quarkus.http.port / quarkus.management.port and quarkus.http.host in application.properties for conflicts or invalid interfaces.
  3. Set the port to 0 (random) in dev mode to dodge conflicts.
  4. Re-run the build with more logging to surface the suppressed cause, since this RuntimeException does not chain the original exception.
  5. Restart the machine/container if a zombie process cannot be found.

Example fix

// before (application.properties)
quarkus.http.port=8080
// after
quarkus.http.port=0   # let the OS pick a free port in dev mode
Defensive patterns

Strategy: validation

Validate before calling

int port = Integer.parseInt(config.httpPort());
try (ServerSocket s = new ServerSocket()) {
    s.bind(new InetSocketAddress(config.httpHost(), port)); // throws if occupied
} catch (BindException e) {
    throw new IllegalStateException("Port " + port + " already in use — stop the other process or use port 0");
}

Prevention

When it happens

Trigger: VertxHttpRecorder.startServerAfterFailedLaunch/dev startup calls virtualBootstrap.bind(VIRTUAL_HTTP).sync() and the bind fails: port already occupied, address/interface not resolvable, or permission denied on a privileged port.

Common situations: Another Quarkus instance or process (often a stale dev-mode process) is still holding the virtual http port; quarkus.http.* / management port misconfigured in application.properties; running in a container or CI where the configured bind address is unavailable; the thread was interrupted during bind.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/7b3b04550b58b574. Report an issue: GitHub.