go-delve/delve · error
stub exited while attempting to connect: %v
Error message
stub exited while attempting to connect: %v
What it means
gdbProcess.Dial connects to an already-running gdbserial stub. While waiting for the stub to become connectable it polls the connection in a loop; if at any point the wait channel reports the stub process has terminated, Dial aborts with 'stub exited while attempting to connect' wrapping the exit status.
Source
Thrown at pkg/proc/gdbserial/gdbserver.go:320
return nil, err
}
return nil, fmt.Errorf("stub exited while waiting for connection: %v", status)
}
}
// Dial attempts to connect to the stub.
func (p *gdbProcess) Dial(addr string, path, cmdline string, pid int, debugInfoDirs []string, stopReason proc.StopReason) (*proc.TargetGroup, error) {
for {
conn, err := net.Dial("tcp", addr)
if err == nil {
return p.Connect(conn, path, cmdline, pid, debugInfoDirs, stopReason)
}
select {
case status := <-p.waitChan:
if err := checkRosettaExpensive(); err != nil {
return nil, err
}
return nil, fmt.Errorf("stub exited while attempting to connect: %v", status)
default:
}
time.Sleep(time.Second)
}
}
// Connect connects to a stub and performs a handshake.
//
// Path and pid are, respectively, the path to the executable of the target
// program and the PID of the target process, both are optional, however
// some stubs do not provide ways to determine path and pid automatically
// and Connect will be unable to function without knowing them.
func (p *gdbProcess) Connect(conn net.Conn, path, cmdline string, pid int, debugInfoDirs []string, stopReason proc.StopReason) (*proc.TargetGroup, error) {
p.conn.conn = conn
p.conn.pid = pid
err := p.conn.handshake(p.regnames)
if err != nil {
conn.Close()View on GitHub (pinned to a23773e6c3)
Solutions
- Check the wrapped exit status and inspect the stub's output/logs to see why it terminated before the connection completed.
- Verify the stub process is still alive (ps) at the address you're dialing, and restart it if needed, then connect promptly.
- Ensure only one client connects; a stub typically serves a single connection and exits after another client attaches.
- Use a stable, supported stub version and environment (matching Delve and OS/arch), especially in containers/CI.
Defensive patterns
Strategy: validation
Validate before calling
// before dialing, confirm the stub is listening and alive
conn, err := net.DialTimeout("tcp", addr, 2*time.Second)
if err != nil {
return fmt.Errorf("no stub listening at %s: %w", addr, err)
}
conn.Close() Try / catch
tg, err := dbg.Dial(addr, ...)
if err != nil && strings.Contains(err.Error(), "stub exited while attempting to connect") {
return fmt.Errorf("target stub terminated before connection: %w; restart the headless session", err)
} Prevention
- Connect promptly after the stub reports its listening port
- Allow only one client per stub session
- Monitor the stub process (ps / wait) and surface its logs on failure
- Use matching Delve/stub versions in containers and CI
When it happens
Trigger: Calling debugger.Dial()/connect to a headless stub whose process died while Delve was retrying the connection loop — the stub crashed after printing its port, was killed externally, or exited because another client already connected.
Common situations: Connecting to a `dlv --headless`/lldb-server process that crashed or was terminated before the client attached; two clients racing to connect to the same stub; stale address/port reused after the stub exited; container/CI environments reaping the stub process.
Related errors
- could not connect
- stub exited while waiting for connection: %v
- direction change with internal breakpoints
- can not start a call injection while running backwards
- follow exec not supported
AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31).
Data as JSON: /api/errors/5283efbf08d89d4e.
Report an issue: GitHub.