go-delve/delve · error
error while waiting after adding process: %d %s
Error message
error while waiting after adding process: %d %s
What it means
When registering a new LWP on FreeBSD, addThread enables PTRACE_LWP_EVENTS; if that ptrace returns ESRCH (pid vanished), Delve performs a compensating wait(dbp.pid, 0) to reap the event. If that wait also fails, it returns "error while waiting after adding process: <pid> <err>" — the process state could not be reconciled while adding the thread.
Source
Thrown at pkg/proc/native/proc_freebsd.go:243
}
// Used by RequestManualStop
func (dbp *nativeProcess) requestManualStop() (err error) {
return sys.Kill(dbp.pid, sys.SIGSTOP)
}
// Attach to a newly created thread, and store that thread in our list of
// known threads.
func (dbp *nativeProcess) addThread(tid int, attach bool) (*nativeThread, error) {
if thread, ok := dbp.threads[tid]; ok {
return thread, nil
}
var err error
dbp.execPtraceFunc(func() { err = sys.PtraceLwpEvents(dbp.pid, 1) })
if err == syscall.ESRCH {
if _, _, err = dbp.wait(dbp.pid, 0); err != nil {
return nil, fmt.Errorf("error while waiting after adding process: %d %s", dbp.pid, err)
}
}
dbp.threads[tid] = &nativeThread{
ID: tid,
dbp: dbp,
os: new(osSpecificDetails),
}
if dbp.memthread == nil {
dbp.memthread = dbp.threads[tid]
}
return dbp.threads[tid], nil
}
// Used by initialize
func (dbp *nativeProcess) updateThreadList() error {View on GitHub (pinned to a23773e6c3)
Solutions
- Check whether the debuggee exited concurrently (`ps -p <pid>`); if so, restart the session.
- Ensure no other tracer (or nested dlv) is attached — only one wait can reap events.
- Retry the operation; EINTR/transient wait failures may clear.
- Update Delve if this reproduces reliably on multi-threaded programs (LWP event handling bugs have been fixed historically).
Example fix
// before dlv attach $(pgrep -n shortlived) // process exits during attach // after ./shortlived & # keep it alive, or add a sleep in the target sleep 1 dlv attach $(pgrep shortlived)
Defensive patterns
Strategy: try-catch
Validate before calling
// Ensure no other tracer is attached and the pid is alive:
if _, err := os.FindProcess(pid); err != nil {
return err
}
if _, err := os.Stat(fmt.Sprintf("/proc/%d", pid)); !os.IsNotExist(err) && !isFreeBSD {
// (FreeBSD uses procstat) verify with: procstat -b <pid>
} Try / catch
thr, err := dbp.addThread(tid, true)
if err != nil && strings.Contains(err.Error(), "error while waiting after adding process") {
// process likely exited mid-attach; verify liveness and restart the session
} Prevention
- Attach only to processes expected to stay alive (add sleep/liveness in tests).
- Ensure exactly one tracer is attached to the debuggee.
- Avoid coordinating raw waits on the traced pid outside Delve.
- Keep Delve updated for FreeBSD LWP-event handling fixes.
When it happens
Trigger: Thread creation/attach flow on FreeBSD where sys.PtraceLwpEvents fails with ESRCH and the follow-up wait in addThread returns a non-nil error (child already dead, wait event already consumed, or ECHILD).
Common situations: Debuggee exits while Delve is still discovering threads (short-lived programs); another tracer consumed the wait status; attach to a dying process; wait events consumed by a prior uncoordinated wait.
Related errors
- ptraceGetLwpInfo err %s %d
- could not continue new thread %d %s
- procstat_getprocs returned no processes
- waiting for target execve failed: %s
- wait err %s %d
AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31).
Data as JSON: /api/errors/59a5bbec1c4ec25c.
Report an issue: GitHub.