go-delve/delve · error
could not stop process %d
Error message
could not stop process %d
What it means
waitForStop gives the debuggee's threads a bounded number of chances (16 iterations) to stop; if threads are still running after that, it gives up with "could not stop process <n>". This indicates the mach task_suspend/thread_suspend path could not quiesce the process, leaving the debugger unable to inspect memory safely.
Source
Thrown at pkg/proc/native/proc_darwin.go:398
}
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 {
if err != ErrContinueThread {
return errView on GitHub (pinned to a23773e6c3)
Solutions
- Retry the halt; transient syscall states often clear on a second attempt.
- Inspect what the process is blocked on (sample <pid> or spindump) — uninterruptible syscalls need the syscall to return.
- Kill and restart the debug session if the task is wedged.
- Reduce target thread count or avoid halting during heavy I/O.
- Update Delve/macOS; suspend heuristics differ across OS releases.
Example fix
// before (dlv) halt // while target blocked in unread socket read // after // let the blocking syscall finish or close the peer, then: (dlv) halt
Defensive patterns
Strategy: retry
Validate before calling
// Sample the process to detect uninterruptible waits before halting:
out, err := exec.Command("sample", strconv.Itoa(pid), "1").Output()
_ = out
if err != nil {
return fmt.Errorf("cannot sample pid %d; process may be wedged", pid)
} Try / catch
ports, err := dbp.waitForStop(dbp)
if err != nil && strings.Contains(err.Error(), "could not stop process") {
// threads refused to suspend; back off and retry, or kill/restart the session
} Prevention
- Don't halt while the target is blocked in long uninterruptible syscalls.
- Reduce thread explosion in the debuggee where possible.
- Use `sample`/spindump to understand stuck threads before halting.
- If it wedges repeatedly, kill and relaunch the session instead of looping halts.
When it happens
Trigger: stop() → waitForStop on macOS loops past count > 16 while C.num_running_threads(dbp.os.task) keeps returning > 0: threads ignore suspension, e.g. blocked in unminterruptible kernel states or the task is wedged.
Common situations: Halting a process stuck in uninterruptible syscalls (I/O, network); debuggee with a huge number of threads that can't all suspend in time; kernel/driver issues on specific macOS versions.
Related errors
- error waiting for thread stop %d
- can not run under Rosetta, check that the installed build of
- waitfor duration expired
- could not deliver signal:
- could not resume task
AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31).
Data as JSON: /api/errors/0652573d72f7b0fb.
Report an issue: GitHub.