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

  1. Raise the relevant limits (ulimit -u, ulimit -n, container pids.max and memory) and restart the server
  2. Check dmesg or container events for OOM kills or thread-creation failures at the crash timestamp
  3. If embedding, verify tokio features (rt, net, time, macros) and reuse an existing runtime instead of building a new one
  4. 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

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


AI-assisted analysis of facebook/flow@f88ac94bcf (2026-08-20). Data as JSON: /api/errors/fa2535b68035e37f. Report an issue: GitHub.