go-delve/delve · warning

unable to clear breakpoint %d (partial): %s

Error message

unable to clear breakpoint %d (partial): %s

What it means

Same disableBreakpoint path as the total failure case, but only SOME of the physical breakpoint clears failed (len(errs) < n): at least one target was cleaned successfully while others were not. The '(partial)' marker tells you breakpoint removal succeeded on some processes in the (multi-process) target group but failed on others.

Source

Thrown at pkg/proc/target_group.go:443

				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}
	for t.Next() {
		for _, bp := range t.Breakpoints().M {

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Parse the joined sub-error list to find which targets/addresses failed
  2. Check the liveness of each process in the target group
  3. Retry SetBreakpointEnabled(lbp, false) — already-cleared targets are no-ops
  4. If failed targets are dead, detach/kill the whole group instead
  5. Inspect for stale INT3 bytes if you plan to resume a partially-cleaned process

Example fix

// before
err := grp.SetBreakpointEnabled(lbp, false)
// err: unable to clear breakpoint 7 (partial): could not restore memory at 0x...
// after
if err != nil && strings.Contains(err.Error(), "(partial)") {
    // some targets still have the breakpoint: retry; clears on clean targets are no-ops
    err = grp.SetBreakpointEnabled(lbp, false)
}
Defensive patterns

Strategy: retry

Validate before calling

// check each target before disabling
for _, t := range grp.Targets() {
    if ok, _ := t.Valid(); !ok {
        // skip or clean up this target first
    }
}

Type guard

func isPartialDisableErr(err error) bool {
    return err != nil && strings.Contains(err.Error(), "(partial)")
}

Try / catch

if err := grp.SetBreakpointEnabled(lbp, false); err != nil {
    if isPartialDisableErr(err) {
        // safe to retry: already-cleared targets are no-ops
        time.Sleep(50 * time.Millisecond)
        err = grp.SetBreakpointEnabled(lbp, false)
    }
    return err
}

Prevention

When it happens

Trigger: Calling SetBreakpointEnabled(lbp, false), ChangeBreakpointCondition, or manageUnsatisfiableBreakpoints in a TargetGroup with multiple targets (e.g. after follow-exec forked/exec'd children) where ClearBreakpoint succeeds on some processes but fails on others (child crashed, memory unmapped, ptrace failure) — or on a single target with a breakpoint at multiple addresses where only some clears fail.

Common situations: Multi-process debugging where a child process died mid-session; breakpoint set at several addresses (inlined/multiple instantiations) with mixed clear outcomes; partially failed shutdown sequences.

Related errors


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