go-delve/delve · error
no thread with id %d
Error message
no thread with id %d
What it means
GetThread throws this when the debugger has no OS thread with the requested numeric ID. FindThread(id) returned nil without error, meaning the ID is well-formed but no matching thread exists (or existed) in the target process.
Source
Thrown at service/rpc2/server.go:437
return nil
}
type GetThreadIn struct {
Id int
}
type GetThreadOut struct {
Thread *api.Thread
}
// GetThread gets a thread by its ID.
func (s *RPCServer) GetThread(arg GetThreadIn, out *GetThreadOut) error {
t, err := s.debugger.FindThread(arg.Id)
if err != nil {
return err
}
if t == nil {
return fmt.Errorf("no thread with id %d", arg.Id)
}
_, unlock := s.debugger.LockTargetGroup()
defer unlock()
out.Thread = api.ConvertThread(t, s.debugger.ConvertThreadBreakpoint(t))
return nil
}
type ListPackageVarsIn struct {
Filter string
Cfg api.LoadConfig
}
type ListPackageVarsOut struct {
Variables []api.Variable
}
// ListPackageVars lists all package variables in the context of the current thread.
func (s *RPCServer) ListPackageVars(arg ListPackageVarsIn, out *ListPackageVarsOut) error {View on GitHub (pinned to a23773e6c3)
Solutions
- Re-list threads with ListThreads immediately before GetThread and use a fresh ID
- Handle the error gracefully: the thread exiting between calls is normal in concurrent programs
- Use State/ goroutine APIs (Stacktrace on a goroutine) instead of raw thread IDs when possible, since goroutine IDs are more stable in delve workflows
- Verify the target is running/attached and threads exist before querying
Example fix
// before
thr, err := client.GetThread(rpc2.GetThreadIn{Id: tid}) // tid may be stale
// after
state, _ := client.State(rpc2.StateIn{})
for _, t := range state.Threads {
if t.ID == tid {
thr, err = client.GetThread(rpc2.GetThreadIn{Id: tid})
break
}
} Defensive patterns
Strategy: validation
Validate before calling
func threadExists(client *rpc2.RPCClient, tid int) bool {
st, err := client.State(rpc2.StateIn{})
if err != nil { return false }
for _, t := range st.Threads {
if t.ID == tid { return true }
}
return false
} Try / catch
thr, err := client.GetThread(rpc2.GetThreadIn{Id: tid})
if err != nil && strings.Contains(err.Error(), "no thread with id") {
// thread exited — refresh and continue
return nil
} Prevention
- Re-list threads immediately before use; thread lifetimes are short in concurrent programs
- Prefer goroutine-based APIs (goroutines are delve's primary unit of work)
- Never cache thread IDs across continuations or process restarts
- Check the process is attached and running before thread queries
When it happens
Trigger: Calling RPCClient.GetThread with a thread ID obtained from a previous stop event after the thread exited; an ID that never existed in this process; querying before the target has started, or after it exited, when the thread table is empty.
Common situations: Multithreaded programs where worker threads finish between a ListThreads call and a GetThread call; IDE thread panes caching thread IDs across continuations; attaching to a process after the interesting thread has terminated.
Related errors
- invalid Filter pattern: %v
- len must be less than or equal to %d
- short read
- can not continue execution of core process
- can not change register values of core process
AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31).
Data as JSON: /api/errors/29618f6fb511a964.
Report an issue: GitHub.