go-delve/delve · error

could not get registers trying to step into coroutine: %v

Error message

could not get registers trying to step into coroutine: %v

What it means

Delve implements step-into for Go 1.23+ coroutine-style callbacks (iter.Pull / runtime.newcoro) by reading the closure that will be called. The first step requires the current thread's CPU registers; if Registers() fails (thread exited, process died, or ptrace error), stepping into the coroutine aborts with this wrapped error.

Source

Thrown at pkg/proc/target_exec.go:1766

	}
}

// stepIntoCoroutineMaybe: if the current instruction is a call to a closure
// defined into iter.Pull (i.e. next, yield and stop) stepIntoCoroutineMaybe
// will set up a new breakpoint to step into the associated coroutine code
// and returns true.
// In every other case it returns false.
func stepIntoCoroutineMaybe(curthread Thread, p *Target, text []AsmInstruction) (bool, error) {
	if len(text) == 0 || !text[0].IsCall() || text[0].DestLoc == nil || text[0].DestLoc.Fn == nil || !strings.HasPrefix(text[0].DestLoc.Fn.Name, "iter.Pull") || !strings.Contains(text[0].DestLoc.Fn.Name, ".func") {
		return false, nil
	}
	bi := p.BinInfo()

	// Read the closure that we are going to call currently

	regs, err := curthread.Registers()
	if err != nil {
		return false, fmt.Errorf("could not get registers trying to step into coroutine: %v", err)
	}
	dregs := bi.Arch.RegistersToDwarfRegisters(0, regs)
	cst := text[0].DestLoc.Fn.extra(bi).closureStructType
	clos := newVariable("", dregs.Uint64Val(bi.Arch.ContextRegNum), cst, p.BinInfo(), p.Memory())

	// Get variable 'c' from the current closure, change its type to
	// runtime.coro (it is normally iter.coro, which is an internal
	// placeholder).

	cvar, err := clos.structField("c")
	if err != nil {
		logflags.DebuggerLogger().Errorf("iter.Pull problems accessing captured 'c' variable in closure: %v", err)
		return false, nil
	}
	cvar = cvar.maybeDereference()
	if cvar.Unreadable != nil {
		return false, fmt.Errorf("could not read coroutine: %v", cvar.Unreadable)
	}

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Retry the step — transient thread-exit races usually resolve on the next step command
  2. Verify ptrace permissions (kernel.yama.ptrace_scope, container CAP_SYS_PTRACE / --privileged) if registers are consistently unavailable
  3. Ensure the process has not exited — check target liveness before stepping
  4. Update Delve and Go: newer runtimes/backends handle coroutine closures and thread races more robustly

Example fix

// before: stepping while the target is racing to exit
//   (dlv) step   // thread dies mid-step -> error
// after: confirm the target is alive / retry
//   (dlv) goroutines   // verify goroutine exists
//   (dlv) step         // retry the step
Defensive patterns

Strategy: retry

Try / catch

err := doStep()
if err != nil && strings.Contains(err.Error(), "could not get registers") {
    // thread may have exited mid-step; verify target then retry
    st, stateErr := client.GetState()
    if stateErr == nil && !st.Exited {
        err = doStep()
    }
    return err
}

Prevention

When it happens

Trigger: Calling stepIntoCallback -> stepIntoCoroutineMaybe when curthread.Registers() returns an error — the thread stopped/exited between the step and the register read, or the OS backend failed to fetch registers.

Common situations: Stepping into iterator functions (range-over-func with iter.Pull) while the traced process is under heavy thread churn; attaching to a thread that dies mid-step; ptrace register access failures on some kernels/containers lacking permissions.

Related errors


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