go-delve/delve · error

could not restore registers: %v

Error message

could not restore registers: %v

What it means

At the end of the function-call protocol the runtime asks Delve to restore all registers (except PC/SP) it saved before the call. This error is raised when thread.RestoreRegisters fails on the target thread, meaning the debuggee's register state could not be put back, leaving the thread in a possibly corrupted state.

Source

Thrown at pkg/proc/fncall.go:863

		}
		// get error from top of the stack and return it to user
		errvar, err := readStackVariable(p, thread, regs, archoff, "string", LoadFullValue())
		if err != nil {
			fncall.err = fmt.Errorf("could not get precheck error reason: %v", err)
			break
		}
		errvar.Name = "err"
		fncall.err = fmt.Errorf("%v", constant.StringVal(errvar.Value))

	case debugCallRegCompleteCall: // 0
		p.fncallForG[callScope.g.ID].startThreadID = 0

	case debugCallRegRestoreRegisters: // 16
		// runtime requests that we restore the registers (all except pc and sp),
		// this is also the last step of the function call protocol.
		pc, sp := regs.PC(), regs.SP()
		if err := thread.RestoreRegisters(fncall.savedRegs); err != nil {
			fncall.err = fmt.Errorf("could not restore registers: %v", err)
		}
		if err := setPC(thread, pc); err != nil {
			fncall.err = fmt.Errorf("could not restore PC: %v", err)
		}
		if err := setSP(thread, sp); err != nil {
			fncall.err = fmt.Errorf("could not restore SP: %v", err)
		}
		fncallLog("stepping thread %d", thread.ThreadID())
		if err := stepInstructionOut(callScope.callCtx.grp, p, thread, fncall.debugCallName, fncall.debugCallName); err != nil {
			fncall.err = fmt.Errorf("could not step out of %s: %v", fncall.debugCallName, err)
		}
		if bi.Arch.Name == "amd64" {
			// The tail of debugCallV2 corrupts the state of RFLAGS, we must restore
			// it one extra time after stepping out of it.
			// See https://github.com/go-delve/delve/issues/2985 and
			// TestCallInjectionFlagCorruption
			rflags := bi.Arch.RegistersToDwarfRegisters(0, fncall.savedRegs).Uint64Val(regnum.AMD64_Rflags)
			err := thread.SetReg(regnum.AMD64_Rflags, op.DwarfRegisterFromUint64(rflags))

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Check the target process is still alive before issuing 'call'
  2. Reconnect / restart the debug session — the thread state may be unrecoverable
  3. Retry the call on a stable backend (native instead of core)
  4. Update OS/kernel or Delve if RestoreRegisters fails persistently on your platform
Defensive patterns

Strategy: try-catch

Validate before calling

// Before 'call', verify the process is alive:
// if dbg.Target().Process().Exited() { restart session }

Try / catch

err := dbg.CallFunction(scope, fn, args)
if err != nil && strings.Contains(err.Error(), "could not restore registers") {
	// thread state may be corrupted: restart the debug session
}

Prevention

When it happens

Trigger: funcCallStep handles debugCallRegRestoreRegisters (16) and the backend's RestoreRegisters call returns an error (thread died, ptrace failure, unsupported register set).

Common situations: The debugged process exited or was killed mid-call; native backend ptrace failures on Linux; gdbserial connection dropped during the call; core-dump backend which cannot write registers.

Related errors


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