go-delve/delve · error

qThreadStopInfo mismatch, requested %s got %s

Error message

qThreadStopInfo mismatch, requested %s got %s

What it means

Thrown in the qThreadStopInfo handling when Delve waits (with a 10ms read deadline) for the stop packet for a specific thread and the read times out — no packet arrived in time, so Delve reports that the requested thread ID did not match what it got (nothing). This happens while racing to pick up which thread actually stopped after a continue.

Source

Thrown at pkg/proc/gdbserial/gdbserver_conn.go:1165

	}
	if sp.threadID != threadID {
		// When we send a ^C (manual stop request) and the process is close to
		// stopping anyway, sometimes, debugserver will send back two stop
		// packets. We need to ignore this spurious stop packet. Because the first
		// thing we do after the stop is updateThreadList, which calls this
		// function, this is relatively painless. We simply need to check that the
		// stop packet we receive is for the thread we requested, if it isn't we
		// can assume it is the spurious extra stop packet and simply ignore it.
		// An example of a problematic interaction is in the commit message for
		// this change.
		// See https://github.com/go-delve/delve/issues/3013.

		conn.conn.SetReadDeadline(time.Now().Add(10 * time.Millisecond))
		resp, err = conn.recv(conn.outbuf.Bytes(), "thread stop info", false)
		conn.conn.SetReadDeadline(time.Time{})
		if err != nil {
			if neterr, isneterr := err.(net.Error); isneterr && neterr.Timeout() {
				return stopPacket{}, fmt.Errorf("qThreadStopInfo mismatch, requested %s got %s", sp.threadID, threadID)
			}
			return stopPacket{}, err
		}
		_, sp, err = conn.parseStopPacket(resp, "", nil)
		if err != nil {
			return stopPacket{}, err
		}
		if sp.threadID != threadID {
			return stopPacket{}, fmt.Errorf("qThreadStopInfo mismatch, requested %s got %s", sp.threadID, threadID)
		}
	}

	return sp, nil
}

// restart executes a 'vRun' command.
func (conn *gdbConn) restart(pos string) error {
	conn.outbuf.Reset()

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Retry the operation — it is a timing race and often succeeds on retry
  2. Reduce target/system latency (wired connection instead of network/Wi-Fi, close background load)
  3. Upgrade Delve; timeout handling in qThreadStopInfo has been adjusted in newer versions
  4. If consistently reproducible, capture gdbwire logs and file an issue with the stub details
Defensive patterns

Strategy: retry

Try / catch

sp, err := conn.waitForSpecificStop(threadID)
if err != nil && strings.Contains(err.Error(), "qThreadStopInfo mismatch") {
    select {
    case <-time.After(50 * time.Millisecond):
        return conn.waitForSpecificStop(threadID) // bounded retry
    }
}

Prevention

When it happens

Trigger: After a stop, Delve queries per-thread stop info for threadID; conn.recv times out at the 10ms deadline (net.Error Timeout), and the code converts the timeout into this mismatch error with an empty sp.threadID.

Common situations: Slow or loaded remote targets (network gdbserver, device debugging) where the stub takes longer than 10ms to answer; USB serial latency on iOS debugging; high system load delaying the reply.

Related errors


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