facebook/flow · critical
Failed to create tokio runtime
Error message
Failed to create tokio runtime
What it means
The Flow server's serve loop builds a single-threaded tokio runtime via Builder::new_current_thread().enable_all().build() and expects success (rust_port/crates/flow_server/src/server.rs:283-286). build() fails when tokio cannot set up its I/O and time drivers — practically when it cannot spawn the driver thread or register with epoll/kqueue due to OS resource limits. This expect aborts the whole server process at startup when the environment cannot host an async runtime.
Source
Thrown at rust_port/crates/flow_server/src/server.rs:285
) {
loop {
tokio::task::yield_now().await;
let done = orchestrator.collect_heap_slice(Arc::clone(&committed_heap), 10000);
if done {
break;
}
}
}
fn serve(
_genv: &Genv,
committed_heap: &Arc<flow_heap::heap_state::CommittedHeap>,
orchestrator: &server_orchestrator::ServerOrchestratorHandle,
) {
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("Failed to create tokio runtime");
loop {
monitor_rpc::status_update(server_status::Event::Ready);
let _options = &_genv.options;
let _start_time = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_secs_f64();
runtime.block_on(async {
let orchestrator_for_gc = orchestrator.clone();
let idle_thread = async {
tokio::join!(
idle_logging_loop(Arc::clone(_options), _start_time),
gc_loop(Arc::clone(committed_heap), orchestrator_for_gc),
);
};
let process_updates = |skip_incompatible: bool, updates: &BTreeSet<String>| {View on GitHub (pinned to f88ac94bcf)
Solutions
- Raise the relevant limits (ulimit -u, ulimit -n, container pids.max and memory) and restart the server
- Check dmesg or container events for OOM kills or thread-creation failures at the crash timestamp
- If embedding, verify tokio features (rt, net, time, macros) and reuse an existing runtime instead of building a new one
- Replace the expect with graceful error reporting so startup exits with a diagnostic status instead of a panic
Example fix
// before
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("Failed to create tokio runtime");
// after
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap_or_else(|e| {
eprintln!("failed to init tokio runtime: {e}; check thread/fd/memory limits");
std::process::exit(1);
}); Defensive patterns
Strategy: validation
Validate before calling
// Probe async-runtime prerequisites before serving
let probe = tokio::runtime::Builder::new_current_thread().enable_all().build();
if probe.is_err() {
eprintln!("cannot init tokio runtime; check ulimit -u/-n and memory limits");
std::process::exit(1);
} Prevention
- Set adequate ulimit -n and pids limits in service units or container specs before deploying the server
- Budget one driver thread plus its fds for the tokio runtime in capacity planning
- When embedding, reuse an existing tokio Runtime rather than building a new one per serve call
When it happens
Trigger: Server startup under OS limits: RLIMIT_NPROC or cgroup pids.max exhausted, RLIMIT_NOFILE too low for the driver's epoll fd, seccomp/sandboxes blocking epoll_create or clone, or memory pressure preventing the driver stack allocation. Custom builds of flow_server with tokio compiled without the required features (rt, net, time) fail the same way.
Common situations: Docker/Kubernetes containers with low pids or memory limits; CI sandboxes; many flow server instances per host; embedding flow_server with a trimmed tokio feature set.
Related errors
- Failed to create tokio runtime
- failed to spawn flow_server_main thread
- failed to spawn init thread
- failed to spawn the command executor
- failed to spawn connect_and_make_request_timed thread
AI-assisted analysis of facebook/flow@f88ac94bcf (2026-08-20).
Data as JSON: /api/errors/fa2535b68035e37f.
Report an issue: GitHub.