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
- Retry the halt after checking the target state (`goroutines`, `continue`) — the process may have exited.
- Verify the inferior didn't exec a new binary (task port changes across execve).
- Restart the debug session if the exception port is stale; partial-attach states are not recoverable.
- 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
- Check target liveness before issuing halt.
- Expect halts to fail across execve boundaries; stop before/after the exec.
- Avoid racing halt with program exit in scripts/tests.
- Keep the session single-debugger — no concurrent lldb/dlv on the same task.
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.