{"record":{"id":"59fcfe691afb0bd1","repo":"facebook/flow","slug":"failed-to-spawn-flow-server-main-thread","errorCode":null,"errorMessage":"failed to spawn flow_server_main thread","messagePattern":"failed to spawn flow_server_main thread","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"rust_port/crates/flow_server/src/server.rs","lineNumber":579,"sourceCode":"    };\n    flow_event_logger::worker_exception(&data);\n}\n\npub fn run_from_daemonize(\n    options: Arc<Options>,\n    monitor_channels: Option<monitor_rpc::Channels>,\n    start_cause: server_status::StartCause,\n) {\n    install_panic_hook();\n    let result = std::thread::Builder::new()\n        .name(\"flow_server_main\".to_string())\n        .stack_size(SERVER_MAIN_THREAD_STACK_SIZE)\n        .spawn(move || {\n            std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {\n                run(options, monitor_channels, start_cause);\n            }))\n        })\n        .expect(\"failed to spawn flow_server_main thread\")\n        .join()\n        .unwrap_or_else(Err);\n    match result {\n        Ok(()) => {}\n        Err(e) => {\n            let err_msg = panic_message(&*e);\n            let err_display: &dyn std::fmt::Display = &err_msg;\n            let status = flow_common_exit_status::exit_status_for_panic_message(&err_msg);\n            match status {\n                FlowExitStatus::OutOfSharedMemory => {\n                    let msg = exit_msg_of_exception(err_display, \"Out of shared memory\");\n                    flow_hh_logger::info!(\"{}\", msg);\n                }\n                FlowExitStatus::HashTableFull => {\n                    let msg = exit_msg_of_exception(err_display, \"Hash table is full\");\n                    flow_hh_logger::info!(\"{}\", msg);\n                }\n                FlowExitStatus::HeapFull => {","sourceCodeStart":561,"sourceCodeEnd":597,"githubUrl":"https://github.com/facebook/flow/blob/f88ac94bcf6992f5d5a158854d94613ebb92c6e6/rust_port/crates/flow_server/src/server.rs#L561-L597","documentation":"run_server spawns the dedicated flow_server_main thread with a large fixed stack (SERVER_MAIN_THREAD_STACK_SIZE, needed because the type checker recurses deeply) and expects the spawn to succeed (rust_port/crates/flow_server/src/server.rs:570-580). std::thread::Builder::spawn fails when the OS refuses to create the thread — almost always resource limits, since reserving a large stack plus one more thread crosses a cgroup/rlimit boundary. The expect crashes the launcher immediately; panics inside the thread are handled separately via catch_unwind.","triggerScenarios":"Starting the server when RLIMIT_NPROC / cgroup pids.max is exhausted, when memory limits forbid mapping SERVER_MAIN_THREAD_STACK_SIZE, or when FLOW_STACK_SIZE or the compiled-in stack default is set to an unreasonable value for the host.","commonSituations":"Language servers in memory/pids-constrained containers; many flow servers per host; containers whose memory limit was lowered after initial sizing; FLOW_STACK_SIZE tuned very large.","solutions":["Check the thread budget (ulimit -u, /proc/self/status Threads, container pids.max) and raise it or stop other flow instances","Verify memory headroom covers the configured stack size; lower FLOW_STACK_SIZE if it is oversized","Restart after freeing resources; spawn failure under load spikes is transient","Replace the expect with a retry-then-exit path that reports the io::Error from spawn"],"exampleFix":"// before\n.spawn(move || { ... })\n.expect(\"failed to spawn flow_server_main thread\");\n\n// after\nlet handle = std::thread::Builder::new()\n    .name(\"flow_server_main\".to_string())\n    .stack_size(SERVER_MAIN_THREAD_STACK_SIZE)\n    .spawn(move || { ... });\nmatch handle {\n    Ok(h) => { let _ = h.join(); }\n    Err(e) => {\n        eprintln!(\"cannot spawn flow_server_main: {e}; check nproc/memory limits\");\n        std::process::exit(1);\n    }\n}","handlingStrategy":"validation","validationCode":"// Verify the host can create one more big-stack thread before launching\nlet probe = std::thread::Builder::new()\n    .stack_size(SERVER_MAIN_THREAD_STACK_SIZE)\n    .spawn(Option::<u8>::None);\nif probe.is_err() {\n    eprintln!(\"thread budget exhausted; raise ulimit -u / memory before starting flow\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Size FLOW_STACK_SIZE and SERVER_MAIN_THREAD_STACK_SIZE to actual recursion needs, not worst-case guesses","Cap the number of flow server instances per host or cgroup","Monitor Threads in /proc/<pid>/status and alert before the ceiling"],"tags":["thread-spawn","resource-limits","server-startup","stack-size","panic"],"backgroundTag":"thread-spawn-failed","analyzedSha":"f88ac94bcf6992f5d5a158854d94613ebb92c6e6","analyzedAt":"2026-08-20T10:41:37.992Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}