go-delve/delve · error

unable to clear breakpoint %d: %v

Error message

unable to clear breakpoint %d: %v

What it means

disableBreakpoint attempted to clear every physical breakpoint belonging to the logical breakpoint across all valid targets, and ALL of those clears failed (len(errs) == n). The individual errors are comma-joined into this single message, so the breakpoint remains set in every target.

Source

Thrown at pkg/proc/target_group.go:441

				n++
				err := it.ClearBreakpoint(bp.Addr)
				if err != nil {
					errs = append(errs, err)
				}
			}
		}
	}
	if len(errs) > 0 {
		buf := new(bytes.Buffer)
		for i, err := range errs {
			fmt.Fprintf(buf, "%s", err)
			if i != len(errs)-1 {
				fmt.Fprintf(buf, ", ")
			}
		}

		if len(errs) == n {
			return fmt.Errorf("unable to clear breakpoint %d: %v", lbp.LogicalID, buf.String())
		}
		return fmt.Errorf("unable to clear breakpoint %d (partial): %s", lbp.LogicalID, buf.String())
	}
	return nil
}

// ChangeBreakpointCondition changes the breakpoint condition of lbp.
func (grp *TargetGroup) ChangeBreakpointCondition(lbp *LogicalBreakpoint, cond, hitCond string, hitCondPerG bool) error {
	lbp.cond = nil
	if cond != "" {
		var err error
		lbp.cond, err = parser.ParseExpr(cond)
		if err != nil {
			return err
		}
	}

	t := ValidTargets{Group: grp}

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Read the joined sub-errors to identify the per-target failure reason
  2. Check whether the target process is actually alive (it may have exited despite appearing valid)
  3. If the process is dead, detach/kill the session instead of disabling breakpoints
  4. Retry the disable after resuming or restarting the process
  5. As a last resort, discard the session: the INT3 bytes die with the process

Example fix

// before
err := grp.SetBreakpointEnabled(lbp, false) // fails: process already exited
// after
ok, _ := grp.Valid()
if !ok {
    return client.Detach(true) // process gone, tear down session
}
return grp.SetBreakpointEnabled(lbp, false)
Defensive patterns

Strategy: try-catch

Validate before calling

ok, _ := grp.Valid()
if !ok {
    // all targets invalid; disable is meaningless, tear down instead
    return nil
}

Type guard

func isDisableErr(err error) bool {
    return err != nil && strings.HasPrefix(err.Error(), "unable to clear breakpoint ")
}

Try / catch

if err := grp.SetBreakpointEnabled(lbp, false); err != nil {
    if isDisableErr(err) {
        // every clear failed: process likely dead; abort session instead of retrying
        return grp.Detach(true)
    }
    return err
}

Prevention

When it happens

Trigger: Calling SetBreakpointEnabled(lbp, false), ChangeBreakpointCondition, or manageUnsatisfiableBreakpoints when every ClearBreakpoint call fails — typically because the process memory cannot be read/written (process exited, crashed, or text page unavailable) while the target still reports as valid.

Common situations: Target crashed between stop and disable; breakpoint at an address in memory that was unmapped by exec/runtime; ptrace write failures after the debuggee died; disabling breakpoints during shutdown of a dead process.

Related errors


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