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

  1. Read the subprocess stderr embedded in the message - it is the actual startup failure
  2. Run the same command manually in a shell and fix whatever makes it exit early
  3. Verify the binary path and interpreter in the debug config
  4. 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

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


AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20). Data as JSON: /api/errors/048000b1ca27018c. Report an issue: GitHub.