RightNow-AI/openfang · critical
Failed to create tokio runtime for embedded server
Error message
Failed to create tokio runtime for embedded server
What it means
This panic comes from an `.expect()` in start_server (crates/openfang-desktop/src/server.rs:94) when `tokio::runtime::Builder::new_multi_thread().enable_all().build()` returns an Err. The code spawns a dedicated OS thread and builds a fresh multi-threaded tokio runtime on it to run the embedded axum server, since tokio::spawn-based background agents require a runtime context. Runtime construction can fail because the builder cannot spawn worker threads or initialize internal resources (I/O or time drivers, parking/condvar primitives).
Source
Thrown at crates/openfang-desktop/src/server.rs:94
// Bind to a random free port on localhost (main thread — guarantees port)
let std_listener = TcpListener::bind("127.0.0.1:0")?;
let port = std_listener.local_addr()?.port();
let listen_addr: SocketAddr = std_listener.local_addr()?;
info!("OpenFang embedded server bound to http://127.0.0.1:{port}");
let (shutdown_tx, shutdown_rx) = watch::channel(false);
let kernel_clone = kernel.clone();
let shutdown_initiated = Arc::new(AtomicBool::new(false));
let server_thread = std::thread::Builder::new()
.name("openfang-server".into())
.spawn(move || {
let rt = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.expect("Failed to create tokio runtime for embedded server");
rt.block_on(async move {
// start_background_agents() uses tokio::spawn, so it must
// run inside a tokio runtime context.
kernel_clone.start_background_agents();
run_embedded_server(kernel_clone, std_listener, listen_addr, shutdown_rx).await;
});
})?;
Ok(ServerHandle {
port,
kernel,
shutdown_tx,
server_thread: Some(server_thread),
shutdown_initiated,
})
}
View on GitHub (pinned to acf2587e46)
Solutions
- Check OS resource limits (ulimit -u threads, ulimit -n file descriptors) and raise them for the process.
- Reduce worker thread pressure: configure .worker_threads(N) with a small N to lower thread creation cost.
- Ensure the process is not near its memory/thread budget before start_server is called (leaked threads from earlier failures).
- Replace the expect with proper error propagation (return Result from start_server) and surface the underlying io::Error to logs for diagnosis.
- Verify tokio crate version/features are consistent across the workspace to avoid driver initialization issues.
Example fix
// before
let rt = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.expect("Failed to create tokio runtime for embedded server");
// after
let rt = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.worker_threads(2)
.build()
.map_err(|e| ServerError::RuntimeInit(e.to_string()))?; Defensive patterns
Strategy: try-catch
Validate before calling
// Before spawning the server thread, probe resource headroom
let max_threads = unsafe { libc::sysconf(libc::_SC_THREAD_THREADS_MAX) };
if max_threads != -1 && max_threads < 8 {
return Err("too few threads allowed for tokio runtime");
} Try / catch
let rt = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build();
match rt {
Ok(rt) => { /* block_on(...) */ }
Err(e) => log::error!("tokio runtime init failed: {e}"), // propagate to UI/notification
} Prevention
- Run the app with sane ulimits (threads and file descriptors) in containers and CI.
- Avoid spawning unbounded threads before start_server; use a thread pool.
- Configure an explicit small worker_threads count so runtime init needs minimal resources.
- Never expect() on runtime build in shipped code — return Result and degrade gracefully (e.g. fall back to no embedded server).
When it happens
Trigger: Calling tokio Runtime::build() inside the spawned 'openfang-server' thread when the OS refuses to create worker threads (thread count/RLIMIT limits, out of memory), or when the tokio io/time driver resources cannot be created (e.g. epoll/kqueue fd exhaustion).
Common situations: Host environments with very low thread or file-descriptor limits (containers, CI sandboxes), heavily memory-constrained machines, or misconfigured tokio features (missing 'rt-multi-thread'/'macros' features is caught at compile time, but runtime resource exhaustion hits here).
Related errors
- Failed to create Tokio runtime
- Failed to set listener to non-blocking
- Failed to convert std TcpListener to tokio
- Failed to decode tray icon PNG
- Failed to listen for SIGINT
AI-assisted analysis of RightNow-AI/openfang@acf2587e46 (2026-09-02).
Data as JSON: /api/errors/46712d4b6d316e38.
Report an issue: GitHub.