{"record":{"id":"c0d931705448afb9","repo":"RightNow-AI/openfang","slug":"failed-to-convert-std-tcplistener-to-tokio","errorCode":null,"errorMessage":"Failed to convert std TcpListener to tokio","messagePattern":"Failed to convert std TcpListener to tokio","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/openfang-desktop/src/server.rs","lineNumber":128,"sourceCode":"    })\n}\n\n/// Run the axum server inside a tokio runtime, shut down when the watch\n/// channel fires.\nasync fn run_embedded_server(\n    kernel: Arc<OpenFangKernel>,\n    std_listener: TcpListener,\n    listen_addr: SocketAddr,\n    mut shutdown_rx: watch::Receiver<bool>,\n) {\n    let (app, state) = build_router(kernel, listen_addr).await;\n\n    // Convert std TcpListener → tokio TcpListener\n    std_listener\n        .set_nonblocking(true)\n        .expect(\"Failed to set listener to non-blocking\");\n    let listener = tokio::net::TcpListener::from_std(std_listener)\n        .expect(\"Failed to convert std TcpListener to tokio\");\n\n    info!(\"OpenFang embedded server listening on http://{listen_addr}\");\n\n    let server = axum::serve(\n        listener,\n        app.into_make_service_with_connect_info::<SocketAddr>(),\n    )\n    .with_graceful_shutdown(async move {\n        let _ = shutdown_rx.wait_for(|v| *v).await;\n        info!(\"Embedded server received shutdown signal\");\n    });\n\n    if let Err(e) = server.await {\n        error!(\"Embedded server error: {e}\");\n    }\n\n    // Clean up channel bridges\n    {","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/RightNow-AI/openfang/blob/acf2587e46be174c10200489c9a2d23a39a98aeb/crates/openfang-desktop/src/server.rs#L110-L146","documentation":"This panic comes from `tokio::net::TcpListener::from_std(std_listener).expect(...)` in run_embedded_server (crates/openfang-desktop/src/server.rs:128). from_std converts an already-bound, already-listening std TcpListener into a tokio one by registering it with the tokio runtime's I/O driver. It fails if the socket is in blocking mode, the fd cannot be registered with epoll/kqueue, or the runtime has no I/O driver enabled.","triggerScenarios":"(1) Skipping or failing the preceding set_nonblocking(true) call; (2) calling from_std outside a runtime with enable_io() (here it runs inside rt.block_on, so the driver exists, but fd registration can still fail); (3) fd exhaustion or the socket being closed before conversion.","commonSituations":"Adapting this code into a context whose runtime was built without .enable_all()/.enable_io(); refactoring that drops the set_nonblocking step; running in containers with exhausted file descriptors; passing a listener fd that another component closed.","solutions":["Always call set_nonblocking(true) on the std listener immediately before from_std.","Ensure the conversion happens inside a tokio runtime built with .enable_all() (as start_server does).","Return the io::Error instead of expect-ing so failures log the OS reason (EMFILE, EBADF).","Raise the fd limit if EMFILE occurs under load.","Avoid sharing/closing the raw listener fd concurrently with this conversion."],"exampleFix":"// before\nlet listener = tokio::net::TcpListener::from_std(std_listener)\n    .expect(\"Failed to convert std TcpListener to tokio\");\n// after\nstd_listener.set_nonblocking(true)?;\nlet listener = tokio::net::TcpListener::from_std(std_listener)\n    .map_err(|e| ServerError::ListenerSetup(format!(\"from_std: {e}\")))?;","handlingStrategy":"try-catch","validationCode":"// Ensure listener is non-blocking before from_std\nstd_listener.set_nonblocking(true)?;","typeGuard":null,"tryCatchPattern":"let listener = tokio::net::TcpListener::from_std(std_listener)\n    .map_err(|e| {\n        log::error!(\"std→tokio listener conversion failed: {e}\");\n        e\n    })?; // return Result from run_embedded_server instead of expect","preventionTips":["Build the runtime with .enable_all() so the I/O driver exists before from_std.","Keep from_std inside rt.block_on (or Handle::current context) — never on a bare thread.","Raise RLIMIT_NOFILE in containerized deployments to avoid EMFILE at registration.","Set non-blocking mode first; from_std on a blocking socket is the #1 cause."],"tags":["rust","tokio","networking","tcp","axum"],"backgroundTag":"tcp-listener-from-std-failed","analyzedSha":"acf2587e46be174c10200489c9a2d23a39a98aeb","analyzedAt":"2026-09-02T22:42:28.464Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}