go-delve/delve · error

could not raise mach exception

Error message

could not raise mach exception

What it means

requestManualStop implements Delve's halt by sending a mach EXC_BREAKPOINT exception to the inferior's exception port via raise_exception. If the mach call fails (non-KERN_SUCCESS), the stop request cannot be delivered and the error "could not raise mach exception" is returned.

Source

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

		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) {
	var (
		task          = C.mach_port_t(dbp.os.task)
		thread        = C.mach_port_t(dbp.memthread.os.threadAct)
		exceptionPort = C.mach_port_t(dbp.os.exceptionPort)
	)
	dbp.os.halt = true
	kret := C.raise_exception(task, thread, exceptionPort, C.EXC_BREAKPOINT)
	if kret != C.KERN_SUCCESS {
		return fmt.Errorf("could not raise mach exception")
	}
	return nil
}

var couldNotGetThreadCount = errors.New("could not get thread count")
var couldNotGetThreadList = errors.New("could not get thread list")

func (dbp *nativeProcess) updateThreadList() error {
	return dbp.updateThreadListForTask(dbp.os.task)
}

func (dbp *nativeProcess) updateThreadListForTask(task C.task_t) error {
	var (
		err   error
		kret  C.kern_return_t
		count C.int
		list  []uint32
	)

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Retry the halt after checking the target state (`goroutines`, `continue`) — the process may have exited.
  2. Verify the inferior didn't exec a new binary (task port changes across execve).
  3. Restart the debug session if the exception port is stale; partial-attach states are not recoverable.
  4. Report/reproduce with a minimal case if it happens during normal continue/halt, as it may be a backend bug.

Example fix

// before
(dlv) halt   // inferior already exited -> mach exception fails
// after
(dlv) goroutines   // confirm target still alive
(dlv) halt
Defensive patterns

Strategy: try-catch

Validate before calling

// Confirm the target still exists before requesting a halt:
if !proc.Valid() {
    return fmt.Errorf("target already exited; halt not possible")
}

Try / catch

err := dbp.requestManualStop()
if err != nil && strings.Contains(err.Error(), "could not raise mach exception") {
    // target likely exited or exec'd; re-check target state instead of retrying blindly
}

Prevention

When it happens

Trigger: Calling Stop/requestManualStop while the debuggee is running on macOS when raise_exception fails: the task or exception port is invalid (inferior exited or exec'd and the task port went stale), or the port rights were lost.

Common situations: User presses Ctrl-C / issues `halt` just as the inferior exits or calls execve, invalidating dbp.os.exceptionPort; mach port exhaustion; a prior attach that only partially succeeded leaving ports uninitialized.

Related errors


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