gastownhall/beads · error

commit conflict resolution: %w

Error message

commit conflict resolution: %w

What it means

After all conflicts are resolved, Sync commits the resolution via CommitMergeResolution (not Commit — plain Commit's nothing-to-commit tolerance would silently skip the --ours case where resolution dirties nothing, leaving dolt_merge_status.is_merging true while sync reports Merged=true and pushes). Any failure from that commit is wrapped as 'commit conflict resolution'.

Source

Thrown at internal/storage/embeddeddolt/federation.go:351

			return result, result.Error
		}

		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
			}
		}
		result.ConflictsResolved = true

		// CommitMergeResolution, not Commit: Commit's GH#3886 nothing-to-commit
		// tolerance would swallow the --ours case (resolution dirties nothing)
		// as a silent no-op here, leaving dolt_merge_status.is_merging true while
		// this function reports result.Merged = true and pushes — the exact
		// re-wedge CommitMergeResolution's doc comment describes. See the
		// server-mode twin, dolt/federation.go's Sync.
		if err := s.CommitMergeResolution(ctx, fmt.Sprintf("Resolve conflicts from %s using %s strategy", peer, strategy)); err != nil {
			result.Error = fmt.Errorf("commit conflict resolution: %w", err)
			return result, result.Error
		}

		// bd-578h9.11: the conflicted merge skipped the automatic is_blocked
		// recompute (unresolved rows would have fed it garbage); now that the
		// resolution is committed, cover the whole merge+resolution window.
		if err := s.RecomputeBlockedAfterMerge(ctx, beforeCommit); err != nil {
			result.Error = fmt.Errorf("conflicts resolved but is_blocked recompute failed: %w", err)
			return result, result.Error
		}
	}
	result.Merged = true

	afterCommit, _ := s.GetCurrentCommit(ctx)
	if beforeCommit != afterCommit {
		result.PulledCommits = 1
	}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Check dolt_merge_status — if is_merging is stuck, clear/abort the merge and re-run sync.
  2. Remove stale dolt lock files left by crashed processes, then retry.
  3. Free disk space / fix filesystem permissions on the data directory.
  4. Re-run the whole sync with the same strategy; resolution+commit is idempotent from a clean merge state.

Example fix

// before: wedged is_merging blocks the resolution commit
if err := s.CommitMergeResolution(ctx, msg); err != nil { ... }
// after: verify merge state is clean before attempting sync
if merging, _ := s.isMergeInProgress(ctx); merging {
    return fmt.Errorf("previous merge still in progress; resolve or abort first")
}
if err := s.CommitMergeResolution(ctx, msg); err != nil { ... }
Defensive patterns

Strategy: try-catch

Validate before calling

// refuse to start a new sync while a merge is already in progress
if merging := mergeInProgress(store, ctx); merging {
    return fmt.Errorf("previous merge still in progress; resolve or abort first")
}

Try / catch

result, err := store.Sync(ctx, peer, strategy)
if err != nil && strings.Contains(err.Error(), "commit conflict resolution") {
    // clear stuck is_merging state, then retry the full sync
    if aerr := abortStuckMerge(ctx, store); aerr == nil {
        result, err = store.Sync(ctx, peer, strategy)
    }
}

Prevention

When it happens

Trigger: store.Sync(ctx, peer, strategy) where CommitMergeResolution(ctx, "Resolve conflicts from <peer> using <strategy> strategy") errors: DOLT_COMMIT fails on the resolution working set, stale merge state, lock files, or I/O failure.

Common situations: Stale is_merging state from a previous wedged sync; disk full during the resolution commit; concurrent process touched the working set between resolution and commit.

Related errors


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