{"record":{"id":"3d47ae74bdf793ae","repo":"go-delve/delve","slug":"could-not-deliver-signal","errorCode":null,"errorMessage":"could not deliver signal: ","messagePattern":"could not deliver signal: ","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/proc/native/proc_darwin.go","lineNumber":191,"sourceCode":"\t\treturn nil, err\n\t}\n\n\ttgt, err := dbp.initialize(\"\", []string{})\n\tif err != nil {\n\t\tdetachWithoutGroup(dbp, false)\n\t\treturn nil, err\n\t}\n\treturn tgt, nil\n}\n\n// Kill kills the process.\nfunc (procgrp *processGroup) kill(dbp *nativeProcess) (err error) {\n\tif ok, _ := dbp.Valid(); !ok {\n\t\treturn nil\n\t}\n\terr = sys.Kill(-dbp.pid, sys.SIGKILL)\n\tif err != nil {\n\t\treturn errors.New(\"could not deliver signal: \" + err.Error())\n\t}\n\tfor port := range dbp.threads {\n\t\tif C.thread_resume(C.thread_act_t(port)) != C.KERN_SUCCESS {\n\t\t\treturn errors.New(\"could not resume task\")\n\t\t}\n\t}\n\tfor {\n\t\tvar task C.task_t\n\t\tport := C.mach_port_wait(dbp.os.portSet, &task, C.int(0))\n\t\tif port == dbp.os.notificationPort {\n\t\t\tbreak\n\t\t}\n\t}\n\tdbp.postExit()\n\treturn\n}\n\nfunc (dbp *nativeProcess) requestManualStop() (err error) {","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/go-delve/delve/blob/a23773e6c31361e43246bc43a424ee009679b174/pkg/proc/native/proc_darwin.go#L173-L209","documentation":"On macOS, kill() sends SIGKILL to the process group (-dbp.pid) via sys.Kill. If that kill syscall fails, the error is wrapped as 'could not deliver signal: <errno>'. This usually means the debugged task is already gone or the signal could not be delivered to the group.","triggerScenarios":"Calling kill (detach after kill, or terminating a debug session) on macOS when sys.Kill(-pid, SIGKILL) fails — e.g. ESRCH because the process already exited, or EPERM due to privilege mismatch.","commonSituations":"Debuggee crashed or exited before dlv kills it; user pressed Ctrl-C/quit while the inferior was already dead; dlv running as a different user than the target; SIP restrictions interfering.","solutions":["Check whether the debuggee already exited (kill of a dead pid returns ESRCH) — treat as already-dead and continue detach","Ensure dlv runs with sufficient privileges to signal the target (same user or proper entitlements)","Re-run dlv and quit the session while the inferior is still alive","If SIGKILL to the process group is failing, report upstream — the negative-pid group kill may need adjustment"],"exampleFix":"// before\nerr = sys.Kill(-dbp.pid, sys.SIGKILL)\nif err != nil {\n    return errors.New(\"could not deliver signal: \" + err.Error())\n}\n// after\nerr = sys.Kill(-dbp.pid, sys.SIGKILL)\nif err != nil {\n    if errors.Is(err, syscall.ESRCH) {\n        return nil // process already gone\n    }\n    return fmt.Errorf(\"could not deliver SIGKILL to pid %d: %w\", dbp.pid, err)\n}","handlingStrategy":"try-catch","validationCode":"// check the target still exists before killing it\nif err := syscall.Kill(pid, 0); err != nil {\n    // ESRCH: process already gone; skip the kill\n    return nil\n}","typeGuard":null,"tryCatchPattern":"err := grp.kill(dbp)\nif err != nil {\n    if strings.Contains(err.Error(), \"could not deliver signal\") {\n        if strings.Contains(err.Error(), \"process already finished\") || strings.Contains(err.Error(), \"no such process\") {\n            return nil // treat as success: target already dead\n        }\n    }\n    return err\n}","preventionTips":["Run dlv as the same user (or with sufficient privileges) as the debuggee","Quit debug sessions while the inferior is still alive to avoid racing its exit","Treat ESRCH on kill as a no-op in teardown code","Account for macOS SIP/entitlement constraints when signaling debugged tasks"],"tags":["darwin","signal","sigkill","process-exited"],"backgroundTag":"signal-delivery-failed","analyzedSha":"a23773e6c31361e43246bc43a424ee009679b174","analyzedAt":"2026-08-31T15:12:45.221Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}