facebook/flow · critical
failed to spawn init thread
Error message
failed to spawn init thread
What it means
The standalone server performs first-time initialization on a dedicated thread and expects std::thread::Builder::spawn to succeed ('failed to spawn init thread', rust_port/crates/flow_server/src/standalone.rs:377). The surrounding code carefully handles panics raised inside the init thread; this expect only covers failure to create the thread at all, which is an OS-level refusal: thread/process limits or memory for the thread's stack. When it fires, the accept-loop setup aborts and the server never starts.
Source
Thrown at rust_port/crates/flow_server/src/standalone.rs:377
&init_socket_path,
);
}));
if let Err(payload) = init_result {
let panic_message = payload
.downcast_ref::<&str>()
.copied()
.or_else(|| payload.downcast_ref::<String>().map(String::as_str))
.unwrap_or("unknown panic payload");
eprintln!("Error: server initialization panicked: {}", panic_message);
cleanup_and_exit_with_code(
&init_pids_path,
&init_lock_path,
&init_socket_path,
1,
);
}
})
.expect("failed to spawn init thread");
let connection_slots = Arc::new(ConnectionSlots::new());
for stream in listener.incoming() {
match stream {
Ok(stream) => {
if let Err(e) = stream.set_nodelay(true) {
eprintln!("Error setting TCP_NODELAY on client connection: {}", e);
}
let Some(slot_guard) = connection_slots.try_acquire() else {
eprintln!("Refusing connection: too many concurrent clients");
drop(stream);
continue;
};
let state = state.clone();
let options = self.options.dupe();
let committed_heap = self.committed_heap.dupe();
let pool_workers = self.pool.num_workers();View on GitHub (pinned to f88ac94bcf)
Solutions
- Raise ulimit -u / container pids.max / UserTasksMax, or reduce the number of concurrent flow servers on the host
- Free memory so the init thread's stack can be mapped, then restart
- Replace the expect with the same cleanup_and_exit_with_code path used for init panics, logging the io::Error from spawn
- Start the server via the monitor daemon, which reports startup failures structurally instead of crashing silently
Example fix
// before
.expect("failed to spawn init thread");
// after
match builder.spawn(move || { ... }) {
Ok(_t) => {}
Err(e) => {
eprintln!("Error: cannot spawn init thread: {e}");
cleanup_and_exit_with_code(&init_pids_path, &init_lock_path, &init_socket_path, 1);
}
} Defensive patterns
Strategy: validation
Validate before calling
// Cheap headroom check before server start
let threads: usize = std::fs::read_to_string("/proc/self/status")
.ok()
.and_then(|s| s.lines().find(|l| l.starts_with("Threads:")).and_then(|l| l.split_whitespace().nth(1).and_then(|n| n.parse().ok())))
.unwrap_or(0);
if threads + 4 >= thread_limit() {
eprintln!("thread headroom too low for server init; raise limits");
} Prevention
- Raise pids.max / ulimit -u / UserTasksMax for service accounts running flow
- One flow server per project; avoid stacking many servers in one cgroup
- Watch for 'cannot create thread' in dmesg as an early warning
When it happens
Trigger: Server startup on a host that has hit RLIMIT_NPROC or cgroup pids.max, or with insufficient memory to map the init thread's stack, typically when many flow servers or other processes already consume the thread budget.
Common situations: Shared CI hosts; containers with pids limits; editors opening multiple projects each starting a flow server; systemd user-session UserTasksMax limits kicking in.
Related errors
- failed to spawn flow_server_main thread
- failed to spawn the command executor
- Failed to create tokio runtime
- failed to spawn connection thread
- failed to spawn recheck_cancel_monitor thread
AI-assisted analysis of facebook/flow@f88ac94bcf (2026-08-20).
Data as JSON: /api/errors/c8dddefce33927f2.
Report an issue: GitHub.