go-delve/delve · error
could not continue new thread %d %s
Error message
could not continue new thread %d %s
What it means
When trapWaitInternal sees a new thread (LWP) on FreeBSD it adds it to the thread map and issues ptrace(PT_CONTINUE) with signal 0 to let it run. If that continue fails with anything other than ESRCH (the tolerated 'thread died meanwhile' case), delve wraps the tid and error. The debugger cannot resume the newly created thread.
Source
Thrown at pkg/proc/native/proc_freebsd.go:405
} else if pl_flags&_PL_FLAG_BORN != 0 {
th, err = dbp.addThread(int(tid), false)
if err != nil {
if err == sys.ESRCH {
// process died while we were adding it
continue
}
return nil, err
}
if mode == trapWaitStepping {
dbp.execPtraceFunc(func() { ptraceSuspend(tid) })
}
if err = dbp.ptraceCont(0); err != nil {
if err == sys.ESRCH {
// thread died while we were adding it
delete(dbp.threads, int(tid))
continue
}
return nil, fmt.Errorf("could not continue new thread %d %s", tid, err)
}
continue
}
}
if th == nil {
continue
}
if mode == trapWaitStepping {
return th, nil
}
if status.StopSignal() == sys.SIGTRAP || status.Continued() {
// Continued in this case means we received the SIGSTOP signal
return th, nil
}
// TODO(dp) alert user about unexpected signals here.View on GitHub (pinned to a23773e6c3)
Solutions
- Run the debugger with sufficient privileges (same user or root) so PT_CONTINUE on every LWP is permitted.
- Retry the operation; if the tid died (ESRCH) delve already tolerates it, other errno values may be transient after attach races.
- Check the underlying errno in the message; EPERM points at credentials/ptrace-scope, EINVAL at kernel state.
- Upgrade FreeBSD/delve if reproducible on valid tids.
Example fix
// before
if err := dbp.Continue(); err != nil { log.Fatal(err) } // could not continue new thread 4242 EPERM
// after
if err := dbp.Continue(); err != nil {
if strings.Contains(err.Error(), "EPERM") {
log.Fatal("delve lacks ptrace permission on target threads; run as same user or root")
}
log.Fatal(err)
} Defensive patterns
Strategy: try-catch
Validate before calling
// check ptrace scope/credentials before debugging on FreeBSD
func checkPrivs() error {
if os.Geteuid() == 0 { return nil }
return fmt.Errorf("run as root or target owner for reliable thread continues")
} Try / catch
err := dbp.Continue()
if err != nil && strings.Contains(err.Error(), "could not continue new thread") {
if strings.Contains(err.Error(), "EPERM") {
log.Fatal("insufficient ptrace privileges for new threads; run as root/same user")
}
// otherwise retry once
err = dbp.Continue()
} Prevention
- Run the debugger with sufficient privileges for every LWP.
- Note ESRCH is tolerated internally; other errno values need privilege investigation.
- Avoid setuid targets that drop traceability.
- Keep FreeBSD/delve versions matched.
When it happens
Trigger: ptraceCont(0) on a just-discovered tid returns an error other than ESRCH — e.g. EPERM because the tracer lost permission, or EINVAL from a bad state — while handling a new-thread stop event.
Common situations: Attaching to processes that spawn threads very rapidly; permission changes (target setuid, container dropping ptrace scope); FreeBSD version-specific PT_CONTINUE quirks.
Related errors
- error while waiting after adding process: %d %s
- wait err %s %d
- ptraceGetLwpInfo err %s %d
- procstat_getprocs returned no processes
- waiting for target execve failed: %s
AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31).
Data as JSON: /api/errors/5dedf7eabde3daec.
Report an issue: GitHub.