vectordotdev/vector · error

Failed to build HTTP server from TCP listener

Error message

Failed to build HTTP server from TCP listener

What it means

After assembling the merged tonic/axum router, the gRPC API server binds hyper to an already-configured std TCP listener via `hyper::Server::from_tcp(std_listener)` and panics if conversion fails. `from_tcp` errors when the listener is invalid (e.g. closed) or when hyper cannot configure it — typically meaning the socket became unusable between creation and server start.

Solutions

  1. Check that the API address is not already bound and the process has available file descriptors (ulimit -n)
  2. Reproduce with debug logs to confirm whether the listener was closed before serve — fix the shutdown/init race
  3. Retry binding with a fresh listener rather than reusing a possibly-closed std_listener
  4. Run `hyper::Server::from_tcp(...).with_graceful_shutdown(...)` inside a Result chain that surfaces the io::Error instead of panicking

Example fix

// before
hyper::Server::from_tcp(std_listener)
    .expect("Failed to build HTTP server from TCP listener")
// after
let server = hyper::Server::from_tcp(std_listener)
    .map_err(|e| format!("failed to bind API listener: {e}"))?;
Defensive patterns

Strategy: try-catch

Validate before calling

let listener = std::net::TcpListener::bind(api_addr)?; // surface bind errors early
listener.set_nonblocking(true)?;

Try / catch

match hyper::Server::from_tcp(std_listener) {
    Ok(server) => { /* serve */ }
    Err(e) => error!("API listener unusable: {e}"), // io::Error, no panic
}

Prevention

When it happens

Trigger: `start` is invoked with a `std_listener` that `from_tcp` rejects — listener closed/invalid fd, or hyper's TCP configuration (e.g. TCP_NODELAY/nodelay setup) fails on this platform.

Common situations: Socket closed by another component during shutdown race; resource exhaustion (fd limits); platform-specific setsockopt failures in containers or restricted environments.

Related errors


AI-assisted analysis of vectordotdev/vector@bdb87aeaa4 (2026-09-16). Data as JSON: /api/errors/31d526311b24a48b. Report an issue: GitHub.

Appendix: source

Thrown at src/api/grpc_server.rs:105

                    crate::proto::observability::FILE_DESCRIPTOR_SET,
                )
                .register_encoded_file_descriptor_set(tonic_health::pb::FILE_DESCRIPTOR_SET)
                .build()
                .expect("Failed to build reflection service");

            // Build the tonic router (gRPC services) and merge with the HTTP router
            // so both protocols share the same port. `accept_http1(true)` lets plain
            // HTTP/1.1 requests reach the merged axum routes.
            let router = TonicServer::builder()
                .accept_http1(true)
                .add_service(health_service)
                .add_service(ObservabilityServer::new(service))
                .add_service(reflection_service)
                .into_router()
                .merge(http_router(router_serving));

            let result = hyper::Server::from_tcp(std_listener)
                .expect("Failed to build HTTP server from TCP listener")
                .serve(router.into_make_service())
                .with_graceful_shutdown(async {
                    rx.await.ok();
                    info!("GRPC API server shutting down.");
                })
                .await;

            if let Err(e) = result {
                error!(
                    message = "GRPC server encountered an error.",
                    error = %e,
                    error_source = ?e.source(),
                    bind_addr = %actual_addr,
                );
            }
        });

        info!("GRPC API server started on {actual_addr}.");

View on GitHub (pinned to bdb87aeaa4)