go-delve/delve · error
could not set pc
Error message
could not set pc
What it means
On darwin/amd64, nativeThread.setPC calls the Mach wrapper set_pc on the thread act; any kern_return other than KERN_SUCCESS is collapsed into the opaque message 'could not set pc'. The kernel refused to change the instruction pointer of the thread.
Source
Thrown at pkg/proc/native/registers_darwin_amd64.go:122
return 0
}
// TLS returns the value of the register
// that contains the location of the thread
// local storage segment.
func (r *Regs) TLS() uint64 {
return r.gsBase
}
func (r *Regs) GAddr() (uint64, bool) {
return 0, false
}
// SetPC sets the RIP register to the value specified by `pc`.
func (thread *nativeThread) setPC(pc uint64) error {
kret := C.set_pc(thread.os.threadAct, C.uint64_t(pc))
if kret != C.KERN_SUCCESS {
return fmt.Errorf("could not set pc")
}
return nil
}
// SetReg changes the value of the specified register.
func (thread *nativeThread) SetReg(regNum uint64, reg *op.DwarfRegister) error {
if regNum != regnum.AMD64_Rip {
return fmt.Errorf("changing register %d not implemented", regNum)
}
return thread.setPC(reg.Uint64Val)
}
func (r *Regs) Get(n int) (uint64, error) {
reg := x86asm.Reg(n)
const (
mask8 = 0x000f
mask16 = 0x00ff
mask32 = 0xffffView on GitHub (pinned to a23773e6c3)
Solutions
- Check the process is still alive before attempting setPC; treat thread-death races as expected failures
- Re-attach if task/port rights were invalidated (e.g. after the target execed)
- Run delve with proper entitlements/permissions on macOS (SIP constraints, developer mode)
- Log the kern_return code from set_pc to distinguish KERN_INVALID_ARGUMENT vs KERN_TERMINATED for accurate handling
Example fix
// before
kret := C.set_pc(thread.os.threadAct, C.uint64_t(pc))
if kret != C.KERN_SUCCESS {
return fmt.Errorf("could not set pc")
}
// after
kret := C.set_pc(thread.os.threadAct, C.uint64_t(pc))
if kret != C.KERN_SUCCESS {
return fmt.Errorf("could not set pc to 0x%x: kern_return=%d", pc, kret)
} Defensive patterns
Strategy: try-catch
Validate before calling
// before setPC on darwin
if !procAlive(dbp) || !isThreadAlive(dbp, thread.ID) {
return fmt.Errorf("thread gone; cannot set pc")
} Type guard
func isSetPCErr(err error) bool {
return err != nil && strings.Contains(err.Error(), "could not set pc")
} Try / catch
err := thread.setPC(pc)
if isSetPCErr(err) {
// likely thread/process died mid-step; re-sync debugger state
dbp.reattachOrDrop()
return err
} Prevention
- Check process liveness before PC relocation after breakpoint hits
- Expect exit races during step/restart and handle them as non-fatal
- Run with macOS developer mode / proper entitlements to avoid Mach permission failures
- Log kern_return values to diagnose Mach failures
When it happens
Trigger: Setting a new PC during step/restart (e.g. after a breakpoint hit, 'continue' from a breakpoint skipping, or reverse-step machinery) when the thread act is invalid — the thread/process terminated — or Mach privileges were lost.
Common situations: Race where the debuggee exits while delve is relocating the PC off a breakpoint; macOS hardening (SIP/hardened runtime) interfering with task-for-pid; stale thread act after exec.
Related errors
- could not get registers
- changing register %d not implemented
- could not resume task
- could not attach to %d
- error while waiting for task
AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31).
Data as JSON: /api/errors/896c34a4eb24c138.
Report an issue: GitHub.