go-delve/delve · error · couldNotGetThreadCount
could not get thread count
Error message
could not get thread count
What it means
This sentinel error is returned when the Mach `thread_count` call fails (returns -1) while Delve is enumerating the threads of a debugged task on macOS. It means Delve could not determine how many threads exist in the target process, so thread state cannot be synced. It is produced in updateThreadListForTask and surfaces through Launch and updateThreadList.
Source
Thrown at pkg/proc/native/proc_darwin.go:223
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
)
for {
count = C.thread_count(task)
if count == -1 {
return couldNotGetThreadCountView on GitHub (pinned to a23773e6c3)
Solutions
- Re-run the launch/attach; the failure is often transient due to a race with process exit.
- Verify the target process is still alive before launching/attaching (e.g. `ps -p <pid>`).
- On newer macOS, ensure delve is codesigned with the get-task-allow entitlement or run on a machine with debugging permitted (SIP/AMFI settings).
- Retry after disabling hardened runtime restrictions: `codesign --remove-signature <binary>` for dev builds.
- Update delve; Mach task handling is periodically fixed in newer versions.
Defensive patterns
Strategy: try-catch
Validate before calling
// before launching/attaching, ensure the pid is alive
if _, err := os.FindProcess(pid); err != nil {
return fmt.Errorf("target not running: %w", err)
} Type guard
// sentinel check
func isCouldNotGetThreadCount(err error) bool {
return errors.Is(err, errors.New("could not get thread count")) || err != nil && err.Error() == "could not get thread count"
} Try / catch
if err := dlv.Launch(...); err != nil {
if err.Error() == "could not get thread count" {
// process likely exited; retry with a fresh launch
time.Sleep(100 * time.Millisecond)
return dlv.Launch(...)
}
return err
} Prevention
- Verify the target process stays alive during setup (no premature exits).
- Ensure macOS debugging entitlements/signing are configured for delve.
- Avoid attaching to processes in mid-exit; check process state first.
- Keep delve updated; mach port handling improves over releases.
When it happens
Trigger: Calling Launch on macOS (or any operation that triggers dbp.updateThreadList) when the underlying Mach task port is invalid or the task has exited, so C.thread_count(task) returns -1.
Common situations: Debugging a target that died or exited between launch and the thread-list refresh; attaching/launching under a hardened-runtime/signature configuration where Mach task ports are restricted; stale task port after process termination.
Related errors
- could not get thread list
- procstat_getprocs returned no processes
- not implemented
- bad access
- bad instruction
AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31).
Data as JSON: /api/errors/79c9d9f033d10a5a.
Report an issue: GitHub.