go-delve/delve · warning

registers inside callback returned err

Error message

registers inside callback returned err

What it means

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.

Source

Thrown at service/debugger/debugger.go:1493

					// calculated by referring to the stack and the mechanism is similar to that
					// used in pkg/terminal/command.go:printTraceOutput
					rootindex := -1
					for i := len(rawlocs) - 1; i >= 0; i-- {
						if rawlocs[i].Call.Fn.Name == rootstr {
							if rootindex == -1 {
								rootindex = i
								break
							}
						}
					}
					sdepth := rootindex + 1

					if sdepth+1 > followCalls {
						return false, nil
					}
					regs, err := th.Registers()
					if err != nil {
						return false, fmt.Errorf("registers inside callback returned err")

					}
					// Disassemble the instruction at the current PC to get the call destination
					pc := instr.Loc.PC
					maxInstLen := uint64(tgt.BinInfo().Arch.MaxInstructionLength())
					disasm, err := proc.Disassemble(t.Memory(), regs, t.Breakpoints(), tgt.BinInfo(), pc, pc+maxInstLen)
					if err != nil {
						return false, fmt.Errorf("failed to disassemble instruction: %w", err)
					}

					// Extract address from the decoded instruction's destination location
					var addr uint64
					if len(disasm) > 0 && disasm[0].DestLoc != nil {
						addr = disasm[0].DestLoc.PC
					} else {
						return false, fmt.Errorf("failed to extract call destination from instruction at PC %#x", pc)
					}
					fn := tgt.BinInfo().PCToFunc(addr)

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Re-run the trace — this is often a transient thread-lifetime race.
  2. Reduce followCalls so fewer dynamic breakpoints/callbacks fire.
  3. 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.
  4. Check OS-level debugger health (ptrace permissions, yama/ptrace_scope, thread limits).
  5. Update Delve; callback robustness in follow-calls tracing continues to be improved.

Example fix

// before
// fixture goroutine calls the traced function and exits immediately
func worker() { traced() }
// after
func worker() { traced(); runtime.Gosched() } // keep thread alive past the call
Defensive patterns

Strategy: retry

Validate before calling

// ensure the thread is stopped and alive before running follow-calls tracing
state, err := client.GetState()
if err != nil || state.Exited || state.CurrentThread == nil {
    return fmt.Errorf("no live thread to trace: %v", err)
}

Try / catch

_, err := client.Functions(filter, followCalls)
if err != nil && strings.Contains(err.Error(), "registers inside callback") {
    // transient thread-exit race: retry once, then fall back to flat list
    if _, err2 := client.Functions(filter, followCalls-1); err2 != nil {
        _, _ = client.Functions(filter, 0)
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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