go-delve/delve · error
error waiting for thread stop %d
Error message
error waiting for thread stop %d
What it means
waitForStop repeatedly asks all threads of the mach task to stop and consults num_running_threads to check progress. A negative return means the mach thread-count query itself failed (invalid task or thread error), so Delve aborts with "error waiting for thread stop <n>" where n is the negative mach code.
Source
Thrown at pkg/proc/native/proc_darwin.go:396
return th, nil
}
}
func (dbp *nativeProcess) waitForStop() ([]int, error) {
ports := make([]int, 0, len(dbp.threads))
count := 0
for {
var task C.task_t
port := C.mach_port_wait(dbp.os.portSet, &task, C.int(1))
if port != 0 && port != dbp.os.notificationPort && port != C.MACH_RCV_INTERRUPTED {
count = 0
ports = append(ports, int(port))
} else {
n := C.num_running_threads(dbp.os.task)
if n == 0 {
return ports, nil
} else if n < 0 {
return nil, fmt.Errorf("error waiting for thread stop %d", n)
} else if count > 16 {
return nil, fmt.Errorf("could not stop process %d", n)
}
}
}
}
func (dbp *nativeProcess) wait(pid, options int) (int, *sys.WaitStatus, error) {
var status sys.WaitStatus
wpid, err := sys.Wait4(pid, &status, options, nil)
return wpid, &status, err
}
func killProcess(pid int) error {
return sys.Kill(pid, sys.SIGINT)
}
func (dbp *nativeProcess) exitGuard(err error) error {View on GitHub (pinned to a23773e6c3)
Solutions
- Confirm the process is still alive; if it exited, restart the debug session.
- Retry the stop — the exit notification may have raced with the request.
- Check the printed negative code to distinguish task-invalid from thread errors.
- Update macOS/Delve if it recurs with long-running programs (task port validity handling).
Example fix
// before (dlv) halt // issued right as program exits // after (dlv) goroutines // verify target still alive before halting (dlv) halt
Defensive patterns
Strategy: retry
Validate before calling
// Confirm the debuggee is still alive before issuing a stop:
out, err := exec.Command("ps", "-p", strconv.Itoa(dbp.pid)).Output()
if err != nil || len(out) == 0 {
return fmt.Errorf("inferior %d exited; cannot stop", dbp.pid)
} Try / catch
ports, err := dbp.waitForStop(dbp)
if err != nil && strings.Contains(err.Error(), "error waiting for thread stop") {
// negative code printed: likely task died mid-stop; check process state and retry once
} Prevention
- Avoid halting during process shutdown windows.
- Keep debug sessions for long-lived processes rather than near-exit ones.
- Retry the stop once before abandoning the session.
- Watch for external kills (OOM, watchdogs) that invalidate the task port.
When it happens
Trigger: Calling stop (e.g. halt request or before a memory write) on macOS while the inferior task becomes invalid mid-loop — the process exited or was killed during thread enumeration, making C.num_running_threads return < 0.
Common situations: Halt issued just as the inferior crashes or exits; debugging a short-lived process; race between an exit notification and the stop loop.
Related errors
- could not resume task
- could not get thread list
- could not attach to %d
- error while waiting for task
- could not follow task across exec: %d
AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31).
Data as JSON: /api/errors/f7910d32c9157a3a.
Report an issue: GitHub.