{"record":{"id":"f7910d32c9157a3a","repo":"go-delve/delve","slug":"error-waiting-for-thread-stop-d","errorCode":null,"errorMessage":"error waiting for thread stop %d","messagePattern":"error waiting for thread stop (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/proc/native/proc_darwin.go","lineNumber":396,"sourceCode":"\t\treturn th, nil\n\t}\n}\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 {","sourceCodeStart":378,"sourceCodeEnd":414,"githubUrl":"https://github.com/go-delve/delve/blob/a23773e6c31361e43246bc43a424ee009679b174/pkg/proc/native/proc_darwin.go#L378-L414","documentation":"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.","triggerScenarios":"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.","commonSituations":"Halt issued just as the inferior crashes or exits; debugging a short-lived process; race between an exit notification and the stop loop.","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)."],"exampleFix":"// before\n(dlv) halt   // issued right as program exits\n// after\n(dlv) goroutines  // verify target still alive before halting\n(dlv) halt","handlingStrategy":"retry","validationCode":"// Confirm the debuggee is still alive before issuing a stop:\nout, err := exec.Command(\"ps\", \"-p\", strconv.Itoa(dbp.pid)).Output()\nif err != nil || len(out) == 0 {\n    return fmt.Errorf(\"inferior %d exited; cannot stop\", dbp.pid)\n}","typeGuard":null,"tryCatchPattern":"ports, err := dbp.waitForStop(dbp)\nif err != nil && strings.Contains(err.Error(), \"error waiting for thread stop\") {\n    // negative code printed: likely task died mid-stop; check process state and retry once\n}","preventionTips":["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."],"tags":["darwin","threads","mach","stop"],"backgroundTag":"thread-stop-failed","analyzedSha":"a23773e6c31361e43246bc43a424ee009679b174","analyzedAt":"2026-08-31T15:12:45.221Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}