{"record":{"id":"31d526311b24a48b","repo":"vectordotdev/vector","slug":"failed-to-build-http-server-from-tcp-listener","errorCode":null,"errorMessage":"Failed to build HTTP server from TCP listener","messagePattern":"Failed to build HTTP server from TCP listener","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/api/grpc_server.rs","lineNumber":105,"sourceCode":"                    crate::proto::observability::FILE_DESCRIPTOR_SET,\n                )\n                .register_encoded_file_descriptor_set(tonic_health::pb::FILE_DESCRIPTOR_SET)\n                .build()\n                .expect(\"Failed to build reflection service\");\n\n            // Build the tonic router (gRPC services) and merge with the HTTP router\n            // so both protocols share the same port. `accept_http1(true)` lets plain\n            // HTTP/1.1 requests reach the merged axum routes.\n            let router = TonicServer::builder()\n                .accept_http1(true)\n                .add_service(health_service)\n                .add_service(ObservabilityServer::new(service))\n                .add_service(reflection_service)\n                .into_router()\n                .merge(http_router(router_serving));\n\n            let result = hyper::Server::from_tcp(std_listener)\n                .expect(\"Failed to build HTTP server from TCP listener\")\n                .serve(router.into_make_service())\n                .with_graceful_shutdown(async {\n                    rx.await.ok();\n                    info!(\"GRPC API server shutting down.\");\n                })\n                .await;\n\n            if let Err(e) = result {\n                error!(\n                    message = \"GRPC server encountered an error.\",\n                    error = %e,\n                    error_source = ?e.source(),\n                    bind_addr = %actual_addr,\n                );\n            }\n        });\n\n        info!(\"GRPC API server started on {actual_addr}.\");","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/vectordotdev/vector/blob/bdb87aeaa4c4ff27c0ba643c1c77b21bf2ef4013/src/api/grpc_server.rs#L87-L123","documentation":"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.","triggerScenarios":"`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.","commonSituations":"Socket closed by another component during shutdown race; resource exhaustion (fd limits); platform-specific setsockopt failures in containers or restricted environments.","solutions":["Check that the API address is not already bound and the process has available file descriptors (ulimit -n)","Reproduce with debug logs to confirm whether the listener was closed before serve — fix the shutdown/init race","Retry binding with a fresh listener rather than reusing a possibly-closed std_listener","Run `hyper::Server::from_tcp(...).with_graceful_shutdown(...)` inside a Result chain that surfaces the io::Error instead of panicking"],"exampleFix":"// before\nhyper::Server::from_tcp(std_listener)\n    .expect(\"Failed to build HTTP server from TCP listener\")\n// after\nlet server = hyper::Server::from_tcp(std_listener)\n    .map_err(|e| format!(\"failed to bind API listener: {e}\"))?;","handlingStrategy":"try-catch","validationCode":"let listener = std::net::TcpListener::bind(api_addr)?; // surface bind errors early\nlistener.set_nonblocking(true)?;","typeGuard":null,"tryCatchPattern":"match hyper::Server::from_tcp(std_listener) {\n    Ok(server) => { /* serve */ }\n    Err(e) => error!(\"API listener unusable: {e}\"), // io::Error, no panic\n}","preventionTips":["Create the std listener immediately before serving to avoid close races","Check ulimit -n and container fd limits on hosts running the API","Do not reuse listeners across server lifecycles; bind fresh on restart"],"tags":["http","hyper","grpc","rust","startup"],"backgroundTag":"address-already-in-use","analyzedSha":"bdb87aeaa4c4ff27c0ba643c1c77b21bf2ef4013","analyzedAt":"2026-09-16T02:53:35.741Z","contentChangedAt":"2026-09-16T02:53:35.741Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}