gastownhall/beads · error

merge failed: %w

Error message

merge failed: %w

What it means

Sync wraps a failure of Merge(ctx, "<peer>/<branch>") at Step 3. The fetch succeeded but merging the peer's branch into the local branch errored outright — not a conflict outcome, a hard merge failure. The working set may be left mid-merge depending on where the merge failed.

Source

Thrown at internal/storage/dolt/federation.go:377

			}
		}
	}

	// Step 1: Fetch from peer
	if err := s.Fetch(ctx, peer); err != nil {
		result.Error = fmt.Errorf("fetch failed: %w", err)
		return result, result.Error
	}
	result.Fetched = true

	// Step 2: Get status before merge
	beforeCommit, _ := s.GetCurrentCommit(ctx) // Best effort: empty commit hash means diff won't be logged

	// Step 3: Merge peer's branch
	remoteBranch := fmt.Sprintf("%s/%s", peer, s.branch)
	conflicts, err := s.Merge(ctx, remoteBranch)
	if err != nil {
		result.Error = fmt.Errorf("merge failed: %w", err)
		return result, result.Error
	}

	// Step 4: Handle conflicts if any
	if len(conflicts) > 0 {
		result.Conflicts = conflicts

		if strategy == "" {
			// No strategy specified, leave conflicts for manual resolution
			result.Error = fmt.Errorf("merge conflicts require resolution (use --strategy ours|theirs)")
			return result, result.Error
		}

		// Auto-resolve using strategy
		for _, c := range conflicts {
			if err := s.ResolveConflicts(ctx, c.Field, strategy); err != nil {
				result.Error = fmt.Errorf("conflict resolution failed for %s: %w", c.Field, err)
				return result, result.Error

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped cause; check `dolt status` for a wedged merge and abort or complete it
  2. Commit or stash local changes before syncing so the merge starts clean
  3. If history diverged, decide ours/theirs strategy up front or fetch+merge manually
  4. For schema/FK divergence, reconcile rows (delete-vs-insert) before retrying
  5. Verify the remote branch ref exists locally after fetch (`dolt branch -r`)

Example fix

// before: sync into possibly-dirty working set
store.Sync(ctx, peer, "", nil)
// after: ensure clean state first
if err := store.Commit(ctx, "checkpoint"); err != nil && !isNothingToCommit(err) {
    return err
}
store.Sync(ctx, peer, "", nil)
Defensive patterns

Strategy: validation

Validate before calling

// commit any dirty state so merge starts clean
if err := store.Commit(ctx, "pre-sync"); err != nil && !isNothingToCommit(err) {
    return err
}

Type guard

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

Try / catch

result, err := store.Sync(ctx, peer, "", opts)
if isHardMergeFailure(err) {
    // inspect and unwedge working set before retry
    abortOrCompletePendingMerge(); return err
}

Prevention

When it happens

Trigger: Sync Step 3 where s.Merge(ctx, remoteBranch) errors: non-fast-forward with divergent history that cannot auto-merge, uncommitted changes present, schema merge failure (e.g. FK delete-vs-insert divergence that rolls the merge back), or the remote branch missing locally after fetch.

Common situations: Both replicas rewrote history (force-push on peer); mixed-vintage schema_migrations rows (per code comments); merge attempted while the working set is dirty; peer branch deleted upstream so the merged ref doesn't exist.

Related errors


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