{"record":{"id":"87fd74c1e34ba781","repo":"go-delve/delve","slug":"registers-inside-callback-returned-err","errorCode":null,"errorMessage":"registers inside callback returned err","messagePattern":"registers inside callback returned err","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"service/debugger/debugger.go","lineNumber":1493,"sourceCode":"\t\t\t\t\t// calculated by referring to the stack and the mechanism is similar to that\n\t\t\t\t\t// used in pkg/terminal/command.go:printTraceOutput\n\t\t\t\t\trootindex := -1\n\t\t\t\t\tfor i := len(rawlocs) - 1; i >= 0; i-- {\n\t\t\t\t\t\tif rawlocs[i].Call.Fn.Name == rootstr {\n\t\t\t\t\t\t\tif rootindex == -1 {\n\t\t\t\t\t\t\t\trootindex = i\n\t\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tsdepth := rootindex + 1\n\n\t\t\t\t\tif sdepth+1 > followCalls {\n\t\t\t\t\t\treturn false, nil\n\t\t\t\t\t}\n\t\t\t\t\tregs, err := th.Registers()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn false, fmt.Errorf(\"registers inside callback returned err\")\n\n\t\t\t\t\t}\n\t\t\t\t\t// Disassemble the instruction at the current PC to get the call destination\n\t\t\t\t\tpc := instr.Loc.PC\n\t\t\t\t\tmaxInstLen := uint64(tgt.BinInfo().Arch.MaxInstructionLength())\n\t\t\t\t\tdisasm, err := proc.Disassemble(t.Memory(), regs, t.Breakpoints(), tgt.BinInfo(), pc, pc+maxInstLen)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn false, fmt.Errorf(\"failed to disassemble instruction: %w\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\t// Extract address from the decoded instruction's destination location\n\t\t\t\t\tvar addr uint64\n\t\t\t\t\tif len(disasm) > 0 && disasm[0].DestLoc != nil {\n\t\t\t\t\t\taddr = disasm[0].DestLoc.PC\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn false, fmt.Errorf(\"failed to extract call destination from instruction at PC %#x\", pc)\n\t\t\t\t\t}\n\t\t\t\t\tfn := tgt.BinInfo().PCToFunc(addr)","sourceCodeStart":1475,"sourceCodeEnd":1511,"githubUrl":"https://github.com/go-delve/delve/blob/a23773e6c31361e43246bc43a424ee009679b174/service/debugger/debugger.go#L1475-L1511","documentation":"Error produced inside the dynamic-call breakpoint callback when reading the thread's CPU registers (th.Registers()) fails. Registers are needed to disassemble the pending call instruction and extract its runtime destination; without them the dynamic call target cannot be resolved and the callback aborts with this error.","triggerScenarios":"Callback fired on a dynamic call breakpoint during Functions(filter, followCalls>0) trace setup, and th.Registers() fails because the thread has exited between breakpoint hit and callback, the OS ptrace GETREGS call failed (thread in unexpected state, zombie), or the backend (gdbserial/core) cannot supply register state at that moment.","commonSituations":"Multi-threaded programs where the hit thread exits immediately after the call instruction; process crash/exit racing the trace; Windows/remote backends with transient register-read failures; core dumps being stepped incorrectly.","solutions":["Re-run the trace — this is often a transient thread-lifetime race.","Reduce followCalls so fewer dynamic breakpoints/callbacks fire.","Keep the process alive longer around traced calls (e.g. add a final breakpoint or sleep in the fixture) so threads don't exit mid-callback.","Check OS-level debugger health (ptrace permissions, yama/ptrace_scope, thread limits).","Update Delve; callback robustness in follow-calls tracing continues to be improved."],"exampleFix":"// before\n// fixture goroutine calls the traced function and exits immediately\nfunc worker() { traced() }\n// after\nfunc worker() { traced(); runtime.Gosched() } // keep thread alive past the call","handlingStrategy":"retry","validationCode":"// ensure the thread is stopped and alive before running follow-calls tracing\nstate, err := client.GetState()\nif err != nil || state.Exited || state.CurrentThread == nil {\n    return fmt.Errorf(\"no live thread to trace: %v\", err)\n}","typeGuard":null,"tryCatchPattern":"_, err := client.Functions(filter, followCalls)\nif err != nil && strings.Contains(err.Error(), \"registers inside callback\") {\n    // transient thread-exit race: retry once, then fall back to flat list\n    if _, err2 := client.Functions(filter, followCalls-1); err2 != nil {\n        _, _ = client.Functions(filter, 0)\n    }\n}","preventionTips":["Keep traced goroutines alive past the call site to avoid register-read races.","Run the debugger with adequate ptrace permissions (ptrace_scope, CAP_SYS_PTRACE).","Reduce followCalls so fewer dynamic callbacks execute.","Avoid attaching to threads that are about to exit (waitgroup/sync around traced calls).","Check OS thread limits and dmesg for ptrace failures if reproducible."],"tags":["debugger","registers","callback","ptrace"],"backgroundTag":"register-read-failed","analyzedSha":"a23773e6c31361e43246bc43a424ee009679b174","analyzedAt":"2026-08-31T15:12:45.221Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}