go-delve/delve · error

could not resume task

Error message

could not resume task

What it means

After killing the task on macOS, kill() resumes all known thread ports with C.thread_resume. If any Mach thread_resume call does not return KERN_SUCCESS, 'could not resume task' is returned — a Mach port/thread state failure during teardown.

Source

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

	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) {
	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)

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Verify the task is still valid before resuming threads; skip/ignore resume errors after SIGKILL since the task is being killed anyway
  2. Clear stale thread entries from dbp.threads when threads terminate during the session
  3. Ensure SIGKILL actually succeeded before resuming (check the preceding error)
  4. Report upstream if reproducible — teardown should tolerate KERN_TERMINATED/KERN_INVALID_RIGHT from thread_resume

Example fix

// before
for port := range dbp.threads {
    if C.thread_resume(C.thread_act_t(port)) != C.KERN_SUCCESS {
        return errors.New("could not resume task")
    }
}
// after
for port := range dbp.threads {
    if kr := C.thread_resume(C.thread_act_t(port)); kr != C.KERN_SUCCESS && kr != C.KERN_TERMINATED && kr != C.KERN_INVALID_RIGHT {
        return fmt.Errorf("could not resume task: mach error %d", kr)
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// verify the task is still alive before attempting per-thread resume
if err := syscall.Kill(pid, 0); err != nil {
    // task already dead: skip thread_resume loop entirely
    return nil
}

Try / catch

err := grp.kill(dbp)
if err != nil && strings.Contains(err.Error(), "could not resume task") {
    // after SIGKILL a failed thread_resume is usually harmless teardown noise
    log.Println("non-fatal: thread_resume failed during kill", err)
    err = nil
}

Prevention

When it happens

Trigger: kill() iterating dbp.threads when a thread port is stale (thread already terminated), invalid, or the task is already dead, so thread_resume returns an error other than KERN_SUCCESS.

Common situations: Debuggee died between SIGKILL and the resume loop (stale thread ports in the map); thread terminated mid-session and its port became invalid; Mach port right revoked after task death.

Related errors


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