{"record":{"id":"0652573d72f7b0fb","repo":"go-delve/delve","slug":"could-not-stop-process-d","errorCode":null,"errorMessage":"could not stop process %d","messagePattern":"could not stop process (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/proc/native/proc_darwin.go","lineNumber":398,"sourceCode":"}\n\nfunc (dbp *nativeProcess) waitForStop() ([]int, error) {\n\tports := make([]int, 0, len(dbp.threads))\n\tcount := 0\n\tfor {\n\t\tvar task C.task_t\n\t\tport := C.mach_port_wait(dbp.os.portSet, &task, C.int(1))\n\t\tif port != 0 && port != dbp.os.notificationPort && port != C.MACH_RCV_INTERRUPTED {\n\t\t\tcount = 0\n\t\t\tports = append(ports, int(port))\n\t\t} else {\n\t\t\tn := C.num_running_threads(dbp.os.task)\n\t\t\tif n == 0 {\n\t\t\t\treturn ports, nil\n\t\t\t} else if n < 0 {\n\t\t\t\treturn nil, fmt.Errorf(\"error waiting for thread stop %d\", n)\n\t\t\t} else if count > 16 {\n\t\t\t\treturn nil, fmt.Errorf(\"could not stop process %d\", n)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (dbp *nativeProcess) wait(pid, options int) (int, *sys.WaitStatus, error) {\n\tvar status sys.WaitStatus\n\twpid, err := sys.Wait4(pid, &status, options, nil)\n\treturn wpid, &status, err\n}\n\nfunc killProcess(pid int) error {\n\treturn sys.Kill(pid, sys.SIGINT)\n}\n\nfunc (dbp *nativeProcess) exitGuard(err error) error {\n\tif err != ErrContinueThread {\n\t\treturn err","sourceCodeStart":380,"sourceCodeEnd":416,"githubUrl":"https://github.com/go-delve/delve/blob/a23773e6c31361e43246bc43a424ee009679b174/pkg/proc/native/proc_darwin.go#L380-L416","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n(dlv) halt   // while target blocked in unread socket read\n// after\n// let the blocking syscall finish or close the peer, then:\n(dlv) halt","handlingStrategy":"retry","validationCode":"// Sample the process to detect uninterruptible waits before halting:\nout, err := exec.Command(\"sample\", strconv.Itoa(pid), \"1\").Output()\n_ = out\nif err != nil {\n    return fmt.Errorf(\"cannot sample pid %d; process may be wedged\", pid)\n}","typeGuard":null,"tryCatchPattern":"ports, err := dbp.waitForStop(dbp)\nif err != nil && strings.Contains(err.Error(), \"could not stop process\") {\n    // threads refused to suspend; back off and retry, or kill/restart the session\n}","preventionTips":["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."],"tags":["darwin","threads","suspend","timeout"],"backgroundTag":"process-stop-timeout","analyzedSha":"a23773e6c31361e43246bc43a424ee009679b174","analyzedAt":"2026-08-31T15:12:45.221Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}