{"record":{"id":"8cedca3e48d6c37a","repo":"go-delve/delve","slug":"could-not-find-watchpoint-at-address-x","errorCode":null,"errorMessage":"could not find watchpoint at address %#x","messagePattern":"could not find watchpoint at address %#x","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/proc/gdbserial/gdbserver.go","lineNumber":1986,"sourceCode":"\t// t.watchAddr on certain mach kernel versions could contain the address of a\n\t// software breakpoint, hardcoded breakpoint (e.g. runtime.Breakpoint) or a\n\t// hardware watchpoint. The mach exception produced by the kernel *should* disambiguate\n\t// but it doesn't.\n\tif t.watchAddr > 0 {\n\t\tt.CurrentBreakpoint.Breakpoint = t.p.Breakpoints().M[t.watchAddr]\n\t\tif t.CurrentBreakpoint.Breakpoint == nil {\n\t\t\tbuf := make([]byte, t.BinInfo().Arch.BreakpointSize())\n\t\t\t_, err := t.p.ReadMemory(buf, t.watchAddr)\n\t\t\tisHardcodedBreakpoint := err == nil && (bytes.Equal(t.BinInfo().Arch.BreakpointInstruction(), buf) || bytes.Equal(t.BinInfo().Arch.AltBreakpointInstruction(), buf))\n\t\t\tif isHardcodedBreakpoint {\n\t\t\t\t// This is a hardcoded breakpoint, ignore.\n\t\t\t\t// TODO(deparker): There's an optimization here since we will do this\n\t\t\t\t// again at a higher level to determine if we've stopped at a hardcoded breakpoint.\n\t\t\t\t// We could set some state here so that we don't do extra work later.\n\t\t\t\tt.watchAddr = 0\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"could not find watchpoint at address %#x\", t.watchAddr)\n\t\t}\n\t\treturn nil\n\t}\n\tif t.watchReg >= 0 {\n\t\tfor _, bp := range t.p.Breakpoints().M {\n\t\t\tif bp.WatchType != 0 && bp.HWBreakIndex == uint8(t.watchReg) {\n\t\t\t\tt.CurrentBreakpoint.Breakpoint = bp\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\tregs, err := t.Registers()\n\tif err != nil {\n\t\treturn err\n\t}\n\tpc := regs.PC()\n\tif bp, ok := t.p.FindBreakpoint(pc); ok {\n\t\tif t.regs.PC() != bp.Addr {","sourceCodeStart":1968,"sourceCodeEnd":2004,"githubUrl":"https://github.com/go-delve/delve/blob/a23773e6c31361e43246bc43a424ee009679b174/pkg/proc/gdbserial/gdbserver.go#L1968-L2004","documentation":"On macOS (debugserver/mach exceptions), the thread's watchAddr records the address the thread stopped at. SetCurrentBreakpoint tries to match it against known breakpoints; if it is not a known breakpoint, not a hardcoded breakpoint instruction, and not found in the breakpoint map, Delve reports it cannot resolve the watchpoint at that address.","triggerScenarios":"A mach exception reports a stop whose address is neither a Delve-registered breakpoint/watchpoint nor a Go hardcoded breakpoint (runtime.Breakpoint) — e.g. a breakpoint cleared between the stop and SetCurrentBreakpoint, or a foreign/trap instruction injected by something else.","commonSituations":"Clearing breakpoints while threads are concurrently hitting them on macOS; mixing Delve with another debugger/instrumentation injecting INT3s; kernel/dispatch quirks where mach exceptions report software breakpoint addresses ambiguously.","solutions":["Retry the continue; if the breakpoint was cleared concurrently the race typically resolves","Check that no other tool is injecting breakpoint instructions into the target","Update Delve — mach exception watchAddr disambiguation has known fixes on newer macOS versions","If reproducible, capture Delve logs with the watchAddr value and inspect what instruction sits at that address in the target"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// no caller-side pre-check possible; error arises from mach exception disambiguation\nisWatchpointErr := func(err error) bool {\n    return strings.Contains(err.Error(), \"could not find watchpoint at address\")\n}","typeGuard":null,"tryCatchPattern":"err := thread.SetCurrentBreakpoint(false)\nif isWatchpointErr(err) {\n    // race or foreign trap; re-continue and re-evaluate on next stop\n    _ = proc.Continue()\n}","preventionTips":["Do not clear breakpoints while target threads may be hitting them","Avoid running other debuggers/instrumentation that inject traps into the same process","Keep Delve and macOS updated — mach exception handling fixes land regularly","Investigate any reproducible address: read memory there to see what instruction triggered it"],"tags":["gdbserial","macos","watchpoint","mach-exception"],"backgroundTag":"watchpoint-not-found","analyzedSha":"a23773e6c31361e43246bc43a424ee009679b174","analyzedAt":"2026-08-31T15:12:45.221Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}