{"record":{"id":"29618f6fb511a964","repo":"go-delve/delve","slug":"no-thread-with-id-d","errorCode":null,"errorMessage":"no thread with id %d","messagePattern":"no thread with id (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"service/rpc2/server.go","lineNumber":437,"sourceCode":"\treturn nil\n}\n\ntype GetThreadIn struct {\n\tId int\n}\n\ntype GetThreadOut struct {\n\tThread *api.Thread\n}\n\n// GetThread gets a thread by its ID.\nfunc (s *RPCServer) GetThread(arg GetThreadIn, out *GetThreadOut) error {\n\tt, err := s.debugger.FindThread(arg.Id)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif t == nil {\n\t\treturn fmt.Errorf(\"no thread with id %d\", arg.Id)\n\t}\n\t_, unlock := s.debugger.LockTargetGroup()\n\tdefer unlock()\n\tout.Thread = api.ConvertThread(t, s.debugger.ConvertThreadBreakpoint(t))\n\treturn nil\n}\n\ntype ListPackageVarsIn struct {\n\tFilter string\n\tCfg    api.LoadConfig\n}\n\ntype ListPackageVarsOut struct {\n\tVariables []api.Variable\n}\n\n// ListPackageVars lists all package variables in the context of the current thread.\nfunc (s *RPCServer) ListPackageVars(arg ListPackageVarsIn, out *ListPackageVarsOut) error {","sourceCodeStart":419,"sourceCodeEnd":455,"githubUrl":"https://github.com/go-delve/delve/blob/a23773e6c31361e43246bc43a424ee009679b174/service/rpc2/server.go#L419-L455","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nthr, err := client.GetThread(rpc2.GetThreadIn{Id: tid}) // tid may be stale\n// after\nstate, _ := client.State(rpc2.StateIn{})\nfor _, t := range state.Threads {\n    if t.ID == tid {\n        thr, err = client.GetThread(rpc2.GetThreadIn{Id: tid})\n        break\n    }\n}","handlingStrategy":"validation","validationCode":"func threadExists(client *rpc2.RPCClient, tid int) bool {\n    st, err := client.State(rpc2.StateIn{})\n    if err != nil { return false }\n    for _, t := range st.Threads {\n        if t.ID == tid { return true }\n    }\n    return false\n}","typeGuard":null,"tryCatchPattern":"thr, err := client.GetThread(rpc2.GetThreadIn{Id: tid})\nif err != nil && strings.Contains(err.Error(), \"no thread with id\") {\n    // thread exited — refresh and continue\n    return nil\n}","preventionTips":["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"],"tags":["rpc","thread","delve"],"backgroundTag":"thread-not-found","analyzedSha":"a23773e6c31361e43246bc43a424ee009679b174","analyzedAt":"2026-08-31T15:12:45.221Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}