{"record":{"id":"379657d849fadfa0","repo":"FuelLabs/sway","slug":"failed-to-execute-ps-command-379657","errorCode":null,"errorMessage":"Failed to execute ps command","messagePattern":"Failed to execute ps command","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sway-lsp/src/server_state.rs","lineNumber":288,"sourceCode":"                        return;\n                    }\n                }\n            }\n        });\n    }\n\n    /// Spawns a new thread dedicated to checking if the client process is still active,\n    /// and if not, shutting down the server.\n    pub fn spawn_client_heartbeat(&self, client_pid: usize) {\n        tokio::spawn(async move {\n            loop {\n                // Not using sysinfo here because it has compatibility issues with fuel.nix\n                // https://github.com/FuelLabs/fuel.nix/issues/64\n                let output = Command::new(\"ps\")\n                    .arg(\"-p\")\n                    .arg(client_pid.to_string())\n                    .output()\n                    .expect(\"Failed to execute ps command\");\n\n                if String::from_utf8_lossy(&output.stdout).contains(&format!(\"{client_pid} \")) {\n                    tracing::trace!(\"Client Heartbeat: still running ({client_pid})\");\n                } else {\n                    std::process::exit(0);\n                }\n                tokio::time::sleep(std::time::Duration::from_secs(60)).await;\n            }\n        });\n    }\n\n    /// Waits asynchronously for the `is_compiling` flag to become false.\n    ///\n    /// This function checks the state of `is_compiling`, and if it's true,\n    /// it awaits on a notification. Once notified, it checks again, repeating\n    /// this process until `is_compiling` becomes false.\n    pub async fn wait_for_parsing(&self) {\n        loop {","sourceCodeStart":270,"sourceCodeEnd":306,"githubUrl":"https://github.com/FuelLabs/sway/blob/47e5e902faa42baf652dd6a0c88cd23390c1a614/sway-lsp/src/server_state.rs#L270-L306","documentation":"sway-lsp spawns a background tokio task that, every 60 seconds, runs `ps -p <client_pid>` to verify the editor is still alive; if the PID disappears the server exits cleanly. This expect panics when ps itself cannot be spawned (sysinfo is deliberately avoided per the fuel.nix comment). The panic kills the heartbeat task, silently stopping client monitoring — or crashes the server outright under panic=abort.","triggerScenarios":"The LSP server runs where /usr/bin/ps is missing (distroless/minimal containers, devcontainers without procps) or where seccomp policy blocks spawning subprocesses; heartbeat ticks 60s after initialization and panics.","commonSituations":"Running the Fuel LSP inside dockerized editors or CI smoke tests; hardened sandboxes that forbid fork/exec; note the sibling failure — ps works but the editor's PID is in another namespace, making the server exit prematurely.","solutions":["Install procps in the environment hosting sway-lsp (`apt-get install -y procps`).","Run editor and language server in the same PID namespace so `ps -p` can see the client PID.","In restricted sandboxes, allow process spawning for the LSP server's seccomp/AppArmor profile."],"exampleFix":"# before (devcontainer/Dockerfile)\nFROM distroless/base   # no ps; heartbeat panics after 60s\n# after\nFROM debian:bookworm-slim\nRUN apt-get update && apt-get install -y procps && rm -rf /var/lib/apt/lists/*","handlingStrategy":"validation","validationCode":"# before starting the LSP in a container, confirm ps is available\ncommand -v ps >/dev/null 2>&1 || { echo \"sway-lsp heartbeat needs procps\" >&2; exit 1; }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Install procps in devcontainers/images that host sway-lsp.","Run editor and language server in the same PID namespace so the client PID is visible to ps.","For CI LSP smoke tests, prefer `forc check` style runs over full server init if the env cannot spawn ps."],"tags":["rust","sway-lsp","heartbeat","panic","containers","procps","environment"],"backgroundTag":null,"analyzedSha":"47e5e902faa42baf652dd6a0c88cd23390c1a614","analyzedAt":"2026-08-16T07:57:45.555Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}