zed-industries/zed · error
{output} error: process exited before debugger attached.
Error message
{output}
error: process exited before debugger attached. What it means
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.
Source
Thrown at crates/dap/src/transport.rs:627
loop {
match TcpStream::connect(address).await {
Ok(stream) => {
let (read, write) = stream.split();
return Ok((Box::new(write) as _, Box::new(read) as _))
},
Err(_) => {
let has_process = process.lock().is_some();
if has_process {
let status = process.lock().as_mut().unwrap().try_status();
if let Ok(Some(_)) = status {
let child = process.lock().take().unwrap();
let output = child.output().await?;
let output = if output.stderr.is_empty() {
String::from_utf8_lossy(&output.stdout).to_string()
} else {
String::from_utf8_lossy(&output.stderr).to_string()
};
anyhow::bail!("{output}\nerror: process exited before debugger attached.");
}
}
executor.timer(Duration::from_millis(100)).await;
}
}
}
}).fuse() => result
}
})
}
}
impl Drop for TcpTransport {
fn drop(&mut self) {
if let Some(mut p) = self.process.lock().take() {
p.kill().log_err();
}View on GitHub (pinned to f4178619ac)
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`)
Defensive patterns
Strategy: try-catch
Validate before calling
// Dry-run the command before using it as a debug server
let status = util::command::new_std_command(&program)
.args(&args)
.arg("--help")
.output()
.await?;
anyhow::ensure!(status.status.success(), "{program} exits immediately; check interpreter/args"); Try / catch
match connect_tcp_with_process(/* .. */).await {
Ok(io) => Ok(io),
Err(err) if err.to_string().contains("exited before debugger attached") => {
// err already embeds the subprocess stdout/stderr - surface it verbatim to the user
Err(err)
}
Err(err) => Err(err),
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Connection to TCP DAP timeout {address}
- Request failed: {}
- Timed out when connecting to debugger
- Received error response from adapter. Response: {:?}
- When using the `stdio` transport, the path to a debug adapte
AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20).
Data as JSON: /api/errors/048000b1ca27018c.
Report an issue: GitHub.