gastownhall/beads · error
merge conflicts require resolution (use --strategy ours|thei
Error message
merge conflicts require resolution (use --strategy ours|theirs)
What it means
Sync detected merge conflicts but was called without a resolution strategy, so it intentionally stops and leaves conflicts for manual resolution rather than guessing. The conflicts themselves are attached to result.Conflicts. This is a deliberate control-flow error telling the operator to re-run with --strategy ours|theirs or resolve by hand.
Source
Thrown at internal/storage/dolt/federation.go:387
// 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
}
}
result.ConflictsResolved = true
// Commit the resolution INCLUDING config: the operator chose this
// strategy, and plain Commit excludes config (GH#2455). A config-only
// conflict — routine now that kv.memory.* memories sync through config —
// would otherwise resolve but never commit, leaving the merge
// unconcluded and re-wedging the next sync.
if err := s.CommitMergeResolution(ctx, fmt.Sprintf("Resolve conflicts from %s using %s strategy", peer, strategy)); err != nil {View on GitHub (pinned to 71377f2769)
Solutions
- Re-run sync with an explicit strategy: ours keeps local rows, theirs takes peer rows
- Inspect result.Conflicts to see which fields conflict before choosing a strategy
- Resolve conflicts manually (ResolveConflicts per field) then commit and re-sync
- Prevent divergence by syncing more frequently so fewer concurrent edits accumulate
- Decide a house policy (e.g. last-writer-wins via 'theirs') for automated pipelines
Example fix
// before
result, err := store.Sync(ctx, "origin", "", nil)
// after
result, err := store.Sync(ctx, "origin", "theirs", nil)
if result != nil && len(result.Conflicts) > 0 {
log.Printf("auto-resolved %d conflicts using theirs", len(result.Conflicts))
} Defensive patterns
Strategy: fallback
Validate before calling
if strategy != "ours" && strategy != "theirs" && strategy != "" {
return fmt.Errorf("invalid strategy %q", strategy)
} Type guard
func isUnresolvedConflictsErr(err error) bool {
return err != nil && strings.Contains(err.Error(), "require resolution")
} Try / catch
result, err := store.Sync(ctx, peer, strategy, opts)
if isUnresolvedConflictsErr(err) && len(result.Conflicts) > 0 {
// retry with a chosen strategy
result, err = store.Sync(ctx, peer, "theirs", opts)
} Prevention
- Always pass an explicit strategy in automated/CI sync paths
- Inspect result.Conflicts to pick ours vs theirs deliberately
- Sync often to minimize conflicting concurrent edits
When it happens
Trigger: store.Sync(ctx, peer, "" /* empty strategy */, opts) where Step 3's Merge returns a non-empty conflict list.
Common situations: Automated sync jobs that never pass a strategy hitting divergent edits to the same issue rows; two operators editing the same issue on different replicas; first-time federation setup where both sides created overlapping config/kv.memory entries.
Related errors
- conflict resolution failed for %s: %w
- failed to commit conflict resolution: %w
- failed to commit pending changes before sync: %w
- fetch failed: %w
- merge failed: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/3742b2dcb974b62d.
Report an issue: GitHub.