gastownhall/beads · error

merge %s: %w

Error message

merge %s: %w

What it means

PullWithStrategy wraps a failed merge of the freshly fetched tracking ref (<remote>/<branch>) as "merge <ref>: <underlying>". After DOLT_FETCH succeeds, the tracking ref is merged via MergeAndSettleWithStrategy, which auto-resolves safe conflict classes and repairs FK cascades; this error means the merge step itself failed — either an unresolved conflict or a settle-step failure. It is distinct from 4261: the fetch already succeeded, so only the local merge is at fault.

Source

Thrown at internal/storage/versioncontrolops/remotes.go:131

// conflicts TryAutoResolveMergeConflicts declines are, when strategy is
// non-empty, resolved with strategy ("ours" or "theirs") instead of aborting
// the pull for the operator to resolve out-of-band. strategy == "" is exactly
// Pull's behavior. See MergeAndSettleWithStrategy/SettleMerge for the
// resolution logic.
func PullWithStrategy(ctx context.Context, db DBConn, remote, branch, user, strategy string) error {
	if err := withRemoteEnvGuards(func() error {
		if user != "" {
			_, err := db.ExecContext(ctx, "CALL DOLT_FETCH('--user', ?, ?, ?)", user, remote, branch)
			return err
		}
		_, err := db.ExecContext(ctx, "CALL DOLT_FETCH(?, ?)", remote, branch)
		return err
	}); err != nil {
		return fmt.Errorf("fetch from %s/%s: %w", remote, branch, err)
	}
	trackingRef := remote + "/" + branch
	if err := MergeAndSettleWithStrategy(ctx, db, trackingRef, strategy); err != nil {
		return fmt.Errorf("merge %s: %w", trackingRef, err)
	}
	return nil
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Retry the pull with a strategy: use the PullWithStrategy variant (or bd vc pull --strategy ours|theirs) to force-resolve declined conflicts.
  2. Commit or clear local working-set changes before pulling so the merge has a clean base.
  3. Ensure the db passed is a single (pinned) session as MergeAndSettle requires.
  4. Read the wrapped error: for FK violations repair the conflicting rows, then re-run the pull.

Example fix

// before
err := versioncontrolops.Pull(ctx, db, "origin", "main", "") // conflict aborts pull
// after
err := versioncontrolops.PullWithStrategy(ctx, db, "origin", "main", "", "theirs") // accept remote rows on conflict
Defensive patterns

Strategy: fallback

Validate before calling

st, err := versioncontrolops.Status(ctx, db)
if err != nil { return err }
if len(st.Staged) > 0 || len(st.Unstaged) > 0 {
    return fmt.Errorf("commit or clear working-set changes before pulling")
}

Type guard

func isMergeStepErr(err error) bool {
    return err != nil && strings.HasPrefix(err.Error(), "merge ")
}

Try / catch

err := versioncontrolops.Pull(ctx, db, remote, branch, user)
if isMergeStepErr(err) {
    // fall back to operator-chosen resolution
    err = versioncontrolops.PullWithStrategy(ctx, db, remote, branch, user, "theirs")
    if err != nil { return fmt.Errorf("pull failed even with strategy: %w", err) }
}

Prevention

When it happens

Trigger: Pull/PullWithStrategy when the local and remote branch histories conflict in a way TryAutoResolveMergeConflicts declines and strategy is empty; the merged data violates foreign keys that cannot be repaired; the session is not a single session (MergeAndSettle requires a pinned single-session db); the working set is dirty in a way that blocks the merge.

Common situations: Two machines edited the same issue rows while offline; concurrent uncommitted writes on other connections during the pull; operator chose a pull where a --strategy ours|theirs resolution was needed.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/522694edf02171fe. Report an issue: GitHub.