go-delve/delve · error

could not continue new thread %d %s

Error message

could not continue new thread %d %s

What it means

After adding a newly cloned thread (from a PTRACE_EVENT_CLONE/VFORK stop), trapWaitInternal calls th.resume() to let the new thread run. If resuming fails with an errno other than ESRCH (thread already died, which is silently tolerated), Delve aborts the wait loop with this error naming the cloned pid and the underlying errno. It signals the debugger could not return the new thread to execution during thread setup.

Source

Thrown at pkg/proc/native/proc_linux.go:540

				if err == sys.ESRCH {
					// thread died while we were adding it
					delete(dbp.threads, int(cloned))
					continue
				}
				return nil, err
			}
			if halt {
				th.os.running = false
				dbp.threads[int(wpid)].os.running = false
				return nil, nil
			}
			if err = th.resume(); err != nil {
				if err == sys.ESRCH {
					// thread died while we were adding it
					delete(dbp.threads, th.ID)
					continue
				}
				return nil, fmt.Errorf("could not continue new thread %d %s", cloned, err)
			}
			if err = dbp.threads[int(wpid)].resume(); err != nil {
				if err != sys.ESRCH {
					return nil, fmt.Errorf("could not continue existing thread %d %s", wpid, err)
				}
			}
			continue
		}
		if status.StopSignal() == sys.SIGTRAP && (status.TrapCause() == sys.PTRACE_EVENT_EXEC) {
			// A thread called exec and we now have a new process. Retrieve the
			// thread ID of the exec'ing thread with PtraceGetEventMsg to remove it
			// and create a new nativeProcess object to track the new process.
			var tid uint
			dbp.execPtraceFunc(func() { tid, err = sys.PtraceGetEventMsg(wpid) })
			if err == nil {
				delete(dbp.threads, int(tid))
			}
			dbp = newChildProcess(procgrp.procs[0], wpid)

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Retry the debugging session — this is usually a transient race between thread creation and thread exit.
  2. Confirm ptrace permissions (yama ptrace_scope, CAP_SYS_PTRACE in containers).
  3. Ensure nothing else is sending signals to or tracing the new thread concurrently.
  4. If reproducible on a specific workload, capture the errno from the message and report it to the delve project.
Defensive patterns

Strategy: retry

Validate before calling

// check for external signal killers / competing tracers before session
ps -o tracer= -p $PID
cat /proc/sys/kernel/yama/ptrace_scope

Try / catch

if err != nil && strings.Contains(err.Error(), "could not continue new thread") {
    // transient clone/resume race: retry the session after a short delay
    time.Sleep(200 * time.Millisecond)
    retrySession(pid)
}

Prevention

When it happens

Trigger: dbp.addThread(cloned) succeeds but th.resume() (which issues PTRACE_CONT via the backend) fails with EPERM, EIO, or similar non-ESRCH errno for the freshly cloned tid.

Common situations: Race where the new thread exits between addThread and resume but the exit status hasn't been reaped yet (yielding EIO/EPERM instead of ESRCH); ptrace restrictions in hardened containers; kernel version quirks around clone stops.

Related errors


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