{"record":{"id":"031a47708b90738a","repo":"facebook/flow","slug":"lwtsysutils-exec-spawn-failed-ocaml-propagates-as","errorCode":null,"errorMessage":"LwtSysUtils.exec spawn failed; OCaml propagates as rejected Lwt promise","messagePattern":"LwtSysUtils\\.exec spawn failed; OCaml propagates as rejected Lwt promise","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"rust_port/crates/flow_lwt_sys_utils/src/lib.rs","lineNumber":47,"sourceCode":"    env: Option<&[(String, String)]>,\n    cwd: Option<&str>,\n    cmd: &str,\n    args: &[&str],\n) -> CommandResult {\n    let mut command = tokio::process::Command::new(cmd);\n    command.args(args);\n    if let Some(envs) = env {\n        for (k, v) in envs {\n            command.env(k, v);\n        }\n    }\n    if let Some(cwd) = cwd {\n        command.current_dir(cwd);\n    }\n    let output = command\n        .output()\n        .await\n        .expect(\"LwtSysUtils.exec spawn failed; OCaml propagates as rejected Lwt promise\");\n    CommandResult {\n        stdout: String::from_utf8_lossy(&output.stdout).to_string(),\n        stderr: String::from_utf8_lossy(&output.stderr).to_string(),\n        status: output.status,\n    }\n}\n","sourceCodeStart":29,"sourceCodeEnd":54,"githubUrl":"https://github.com/facebook/flow/blob/f88ac94bcf6992f5d5a158854d94613ebb92c6e6/rust_port/crates/flow_lwt_sys_utils/src/lib.rs#L29-L54","documentation":"Panics when the async Command's output() future completes with an Err — the process could not be spawned at all. The message notes the OCaml Lwt original rejects a promise that callers catch; the Rust port panics instead. Spawn errors are almost always NotFound (binary missing from PATH) or PermissionDenied (not executable), not failures of the child itself.","triggerScenarios":"Calling exec for an external tool (git, watchman, shell) that is not installed or not on PATH under the current environment; running under cron/systemd/container where PATH is minimal; the target file exists but lacks the execute bit.","commonSituations":"Minimal Docker images without git; systemd services with PATH=/usr/bin only; watchman absent on CI; scripts passing a relative binary name resolved differently in prod.","solutions":["Install the missing tool or add its directory to PATH for the process","Pre-resolve the binary to an absolute path before spawning","Preflight-check availability (which-style lookup) and degrade gracefully when the tool is optional"],"exampleFix":"// before\nlet output = command.output().await\n    .expect(\"LwtSysUtils.exec spawn failed; OCaml propagates as rejected Lwt promise\");\n\n// after — mirror the OCaml rejected-promise contract\nlet output = match command.output().await {\n    Ok(o) => o,\n    Err(e) => return Err(FlowLspError::ExecFailed { program: program.into(), source: e }),\n};","handlingStrategy":"validation","validationCode":"// Preflight: is the binary resolvable on PATH before spawning?\nfn binary_available(bin: &str) -> bool {\n    std::env::var_os(\"PATH\")\n        .map(|paths| {\n            std::env::split_paths(&paths).any(|dir| {\n                let p = dir.join(bin);\n                p.is_file() && p.metadata().map(|m| !m.permissions().readonly()).unwrap_or(false)\n            })\n        })\n        .unwrap_or(false)\n}","typeGuard":null,"tryCatchPattern":"match command.output().await {\n    Ok(output) => output,\n    Err(e) if e.kind() == std::io::ErrorKind::NotFound => {\n        return Err(FlowLspError::ToolMissing { program: program.into() });\n    }\n    Err(e) => return Err(FlowLspError::ExecFailed { program: program.into(), source: e }),\n}","preventionTips":["Pre-resolve external tools to absolute paths at startup","Set an explicit PATH in service/container environments that run flow","Degrade gracefully when an optional tool (e.g. watchman) is absent"],"tags":["rust","process","spawn","path","command-not-found"],"backgroundTag":"process-spawn-failed","analyzedSha":"f88ac94bcf6992f5d5a158854d94613ebb92c6e6","analyzedAt":"2026-08-20T10:41:37.992Z","contentChangedAt":"2026-08-20T10:41:37.992Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}