go-delve/delve · error

could not find thread %s

Error message

could not find thread %s

What it means

After resuming and waiting for a stop, Delve looks up the thread ID reported by the stub (from the stop packet) in its local thread list via findThreadByStrID. If the stop packet names a thread that was never seen in qThreadStopInfo/jstopInfo or thread list updates, the trap thread is nil and this error is thrown.

Source

Thrown at pkg/proc/gdbserial/gdbserver.go:951

	}

	stopReason := proc.StopUnknown
	if atstart {
		stopReason = proc.StopLaunched
	}

	if p.BinInfo().GOOS == "linux" {
		if err := linutil.ElfUpdateSharedObjects(p); err != nil {
			return nil, stopReason, err
		}
	}

	if err := p.setCurrentBreakpoints(); err != nil {
		return nil, stopReason, err
	}

	if trapthread == nil {
		return nil, stopReason, fmt.Errorf("could not find thread %s", threadID)
	}

	err := machTargetExcToError(trapthread.sig)
	if err != nil {
		// the signals that are reported here can not be propagated back to the target process.
		trapthread.sig = 0
	}
	p.currentThread = trapthread
	return trapthread, stopReason, err
}

func (p *gdbProcess) findThreadByStrID(threadID string) *gdbThread {
	for _, thread := range p.threads {
		if thread.strID == threadID {
			return thread
		}
	}
	return nil

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Retry the continue/step operation — the race often does not recur
  2. Update Delve and the remote stub to versions with consistent thread-stop handling
  3. Capture a log (dlv --log --log-output=rpc,gdbserial) of the stop packets to identify the bogus thread ID and report to the stub vendor
  4. If debugging rr traces, re-record the trace; checkpoint/replay ordering can change which thread reports the stop
Defensive patterns

Strategy: retry

Validate before calling

// no pre-call validation possible; thread state changes asynchronously on the stub
canRetry := func(err error) bool { return strings.Contains(err.Error(), "could not find thread ") }

Try / catch

thread, reason, err := proc.WaitForStop(g)
if err != nil && strings.HasPrefix(err.Error(), "could not find thread ") {
    thread, reason, err = proc.WaitForStop(g) // one retry: transient thread race
}

Prevention

When it happens

Trigger: The stub's stop reply references thread ID X, but updateThreadList/handleThreadSignals never produced a gdbThread with strID X — e.g. the thread exited during the race between resume and stop, or qThreadStopInfo QListThreadsInStopReply data disagrees with the stop packet.

Common situations: Racing thread creation/exit in highly multithreaded inferiors; buggy stubs that report stale or bogus thread IDs in stop packets; rr or debugserver replay quirks where the trapping thread was torn down.

Related errors


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