{"record":{"id":"048000b1ca27018c","repo":"zed-industries/zed","slug":"output-error-process-exited-before-debugger-att","errorCode":null,"errorMessage":"{output}\nerror: process exited before debugger attached.","messagePattern":"(.+?)\nerror: process exited before debugger attached\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/dap/src/transport.rs","lineNumber":627,"sourceCode":"                    loop {\n                        match TcpStream::connect(address).await {\n                            Ok(stream) => {\n                                let (read, write) = stream.split();\n                                return Ok((Box::new(write) as _, Box::new(read) as _))\n                            },\n                            Err(_) => {\n                                let has_process = process.lock().is_some();\n                                if has_process {\n                                    let status = process.lock().as_mut().unwrap().try_status();\n                                    if let Ok(Some(_)) = status {\n                                        let child = process.lock().take().unwrap();\n                                        let output = child.output().await?;\n                                        let output = if output.stderr.is_empty() {\n                                            String::from_utf8_lossy(&output.stdout).to_string()\n                                        } else {\n                                            String::from_utf8_lossy(&output.stderr).to_string()\n                                        };\n                                        anyhow::bail!(\"{output}\\nerror: process exited before debugger attached.\");\n                                    }\n                                }\n\n                                executor.timer(Duration::from_millis(100)).await;\n                            }\n                        }\n                    }\n                }).fuse() => result\n            }\n        })\n    }\n}\n\nimpl Drop for TcpTransport {\n    fn drop(&mut self) {\n        if let Some(mut p) = self.process.lock().take() {\n            p.kill().log_err();\n        }","sourceCodeStart":609,"sourceCodeEnd":645,"githubUrl":"https://github.com/zed-industries/zed/blob/f4178619acd0d47ea1f76a2025c42962c6d6638c/crates/dap/src/transport.rs#L609-L645","documentation":"In the TCP transport's connect retry loop, TcpStream::connect failed while a spawned child process existed and its try_status() showed it had already exited - so Zed collects the child's output (stderr preferred, stdout if stderr empty) and bails with it plus 'error: process exited before debugger attached.' The message explains why the port never opened: the process meant to open it died.","triggerScenarios":"Zed spawns the debuggee/adapter and connects to a port: the process prints an error and exits immediately (wrong interpreter, missing file, bad flag), crashes at startup (shared library missing, segfault), or runs a program that exits instantly without starting a debug server. The collected output names the subprocess failure.","commonSituations":"Wrong binary path in the TCP debug config; script without shebang or wrong interpreter; missing runtime deps (glibc mismatch, PYTHONPATH issues); the debugged app exiting because it expected a TTY/args; server binary that fails to bind the port (already in use) and exits.","solutions":["Read the subprocess stderr embedded in the message - it is the actual startup failure","Run the same command manually in a shell and fix whatever makes it exit early","Verify the binary path and interpreter in the debug config","Ensure the port the process would bind is free (`ss -ltnp`)"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Dry-run the command before using it as a debug server\nlet status = util::command::new_std_command(&program)\n    .args(&args)\n    .arg(\"--help\")\n    .output()\n    .await?;\nanyhow::ensure!(status.status.success(), \"{program} exits immediately; check interpreter/args\");","typeGuard":null,"tryCatchPattern":"match connect_tcp_with_process(/* .. */).await {\n    Ok(io) => Ok(io),\n    Err(err) if err.to_string().contains(\"exited before debugger attached\") => {\n        // err already embeds the subprocess stdout/stderr - surface it verbatim to the user\n        Err(err)\n    }\n    Err(err) => Err(err),\n}","preventionTips":["Test the debug-server command standalone in a shell before configuring it in Zed","Prefer absolute binary paths and verified interpreters in launch configs","Ensure the server binds the configured port and stays alive even when idle"],"tags":["dap","tcp","process-exit","startup","debug-adapter","rust"],"backgroundTag":"process-exited-before-attach","analyzedSha":"f4178619acd0d47ea1f76a2025c42962c6d6638c","analyzedAt":"2026-08-20T19:29:52.058Z","contentChangedAt":"2026-08-20T19:29:52.058Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}