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

  1. Check whether the debuggee exited concurrently (`ps -p <pid>`); if so, restart the session.
  2. Ensure no other tracer (or nested dlv) is attached — only one wait can reap events.
  3. Retry the operation; EINTR/transient wait failures may clear.
  4. 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

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


AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31). Data as JSON: /api/errors/59a5bbec1c4ec25c. Report an issue: GitHub.