{"record":{"id":"8ed6d3343a91de55","repo":"go-delve/delve","slug":"can-not-disable-watchpoints","errorCode":null,"errorMessage":"can not disable watchpoints","messagePattern":"can not disable watchpoints","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"service/debugger/debugger.go","lineNumber":868,"sourceCode":"\td.targetMutex.Lock()\n\tdefer d.targetMutex.Unlock()\n\tif len(d.target.Targets()) != 1 {\n\t\treturn ErrNotImplementedWithMultitarget\n\t}\n\tp := d.target.Selected\n\treturn p.SetEBPFTracepoint(fnName)\n}\n\n// amendBreakpoint will update the breakpoint with the matching ID.\n// It also enables or disables the breakpoint.\n// We can consume this function to avoid locking a goroutine.\nfunc (d *Debugger) amendBreakpoint(amend *api.Breakpoint) error {\n\toriginal := d.target.LogicalBreakpoints[amend.ID]\n\tif original == nil {\n\t\treturn fmt.Errorf(\"no breakpoint with ID %d\", amend.ID)\n\t}\n\tif d.isWatchpoint(original) && amend.Disabled {\n\t\treturn errors.New(\"can not disable watchpoints\")\n\t}\n\terr := d.copyLogicalBreakpointInfo(original, amend)\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = d.target.SetBreakpointEnabled(original, !amend.Disabled)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (d *Debugger) isWatchpoint(lbp *proc.LogicalBreakpoint) bool {\n\tt := proc.ValidTargets{Group: d.target}\n\tfor t.Next() {\n\t\tfor _, bp := range t.Breakpoints().M {\n\t\t\tif bp.LogicalID() == lbp.LogicalID {","sourceCodeStart":850,"sourceCodeEnd":886,"githubUrl":"https://github.com/go-delve/delve/blob/a23773e6c31361e43246bc43a424ee009679b174/service/debugger/debugger.go#L850-L886","documentation":"Watchpoints (data breakpoints on memory addresses/variables) cannot be toggled into the disabled state in Delve; they can only be created or removed. amendBreakpoint rejects any amend request that sets Disabled=true on a logical breakpoint that is a watchpoint.","triggerScenarios":"Calling Debugger.AmendBreakpoint (RPC2 service/amendBreakpoint, DAP update of breakpoints, or terminal `toggle` on a watchpoint) with amend.Disabled == true where d.isWatchpoint(original) is true.","commonSituations":"IDEs that blanket-apply `disabled: true` to all breakpoints when the user disables a group; scripting tools toggling watchpoints like normal line breakpoints; stale UI state re-sending watchpoint configs after the watchpoint was conceptually removed.","solutions":["Clear the watchpoint instead of disabling it (ClearBreakpoint with its ID)","Filter watchpoints out before sending batch disable operations from your frontend","Re-create the watchpoint later when you want it inactive temporarily"],"exampleFix":"// before\namend := &api.Breakpoint{ID: watchpointID, Disabled: true}\nd.AmendBreakpoint(amend) // error\n// after\nd.ClearBreakpoint(watchpointID) // remove; recreate when needed","handlingStrategy":"validation","validationCode":"for _, bp := range toDisable {\n    if isWatchpoint(bp) { // e.g. identified via WatchExpr != \"\" or Addr != 0 && Line == 0\n        clearIDs = append(clearIDs, bp.ID)\n    } else {\n        amendIDs = append(amendIDs, bp.ID)\n    }\n}","typeGuard":"func isWatchpointBP(bp *api.Breakpoint) bool {\n    return bp.WatchExpr != \"\" || bp.Addr != 0 && bp.Line == 0\n}","tryCatchPattern":"err := dbg.AmendBreakpoint(&api.Breakpoint{ID: id, Disabled: true})\nif err != nil && strings.Contains(err.Error(), \"can not disable watchpoints\") {\n    dbg.ClearBreakpoint(id) // remove instead of disable\n}","preventionTips":["In batch-disable UI logic, route watchpoints to ClearBreakpoint instead","Detect watchpoints via their WatchExpr/addr fields before toggling enabled state","Inform users that watchpoints support delete, not pause"],"tags":["watchpoint","breakpoint","unsupported-operation"],"backgroundTag":"unsupported-breakpoint-operation","analyzedSha":"a23773e6c31361e43246bc43a424ee009679b174","analyzedAt":"2026-08-31T15:12:45.221Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}