go-delve/delve · error

could not deliver signal:

Error message

could not deliver signal: 

What it means

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.

Source

Thrown at pkg/proc/native/proc_darwin.go:191

		return nil, err
	}

	tgt, err := dbp.initialize("", []string{})
	if err != nil {
		detachWithoutGroup(dbp, false)
		return nil, err
	}
	return tgt, nil
}

// Kill kills the process.
func (procgrp *processGroup) kill(dbp *nativeProcess) (err error) {
	if ok, _ := dbp.Valid(); !ok {
		return nil
	}
	err = sys.Kill(-dbp.pid, sys.SIGKILL)
	if err != nil {
		return errors.New("could not deliver signal: " + err.Error())
	}
	for port := range dbp.threads {
		if C.thread_resume(C.thread_act_t(port)) != C.KERN_SUCCESS {
			return errors.New("could not resume task")
		}
	}
	for {
		var task C.task_t
		port := C.mach_port_wait(dbp.os.portSet, &task, C.int(0))
		if port == dbp.os.notificationPort {
			break
		}
	}
	dbp.postExit()
	return
}

func (dbp *nativeProcess) requestManualStop() (err error) {

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Check whether the debuggee already exited (kill of a dead pid returns ESRCH) — treat as already-dead and continue detach
  2. Ensure dlv runs with sufficient privileges to signal the target (same user or proper entitlements)
  3. Re-run dlv and quit the session while the inferior is still alive
  4. If SIGKILL to the process group is failing, report upstream — the negative-pid group kill may need adjustment

Example fix

// before
err = sys.Kill(-dbp.pid, sys.SIGKILL)
if err != nil {
    return errors.New("could not deliver signal: " + err.Error())
}
// after
err = sys.Kill(-dbp.pid, sys.SIGKILL)
if err != nil {
    if errors.Is(err, syscall.ESRCH) {
        return nil // process already gone
    }
    return fmt.Errorf("could not deliver SIGKILL to pid %d: %w", dbp.pid, err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// check the target still exists before killing it
if err := syscall.Kill(pid, 0); err != nil {
    // ESRCH: process already gone; skip the kill
    return nil
}

Try / catch

err := grp.kill(dbp)
if err != nil {
    if strings.Contains(err.Error(), "could not deliver signal") {
        if strings.Contains(err.Error(), "process already finished") || strings.Contains(err.Error(), "no such process") {
            return nil // treat as success: target already dead
        }
    }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31). Data as JSON: /api/errors/3d47ae74bdf793ae. Report an issue: GitHub.