{"record":{"id":"a33d9423accd5e0a","repo":"gastownhall/beads","slug":"merge-conflicts-require-resolution-use-strategy-a33d94","errorCode":null,"errorMessage":"merge conflicts require resolution (use --strategy ours|theirs)","messagePattern":"merge conflicts require resolution \\(use --strategy ours\\|theirs\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/embeddeddolt/federation.go","lineNumber":332,"sourceCode":"\tresult.Fetched = true\n\n\t// Step 2: Get commit before merge for change detection\n\tbeforeCommit, _ := s.GetCurrentCommit(ctx)\n\n\t// Step 3: Merge peer's branch\n\tremoteBranch := fmt.Sprintf(\"%s/%s\", peer, s.branch)\n\tconflicts, err := s.Merge(ctx, remoteBranch)\n\tif err != nil {\n\t\tresult.Error = fmt.Errorf(\"merge failed: %w\", err)\n\t\treturn result, result.Error\n\t}\n\n\t// Step 4: Handle conflicts\n\tif len(conflicts) > 0 {\n\t\tresult.Conflicts = conflicts\n\n\t\tif strategy == \"\" {\n\t\t\tresult.Error = fmt.Errorf(\"merge conflicts require resolution (use --strategy ours|theirs)\")\n\t\t\treturn result, result.Error\n\t\t}\n\n\t\tfor _, c := range conflicts {\n\t\t\tif err := s.ResolveConflicts(ctx, c.Field, strategy); err != nil {\n\t\t\t\tresult.Error = fmt.Errorf(\"conflict resolution failed for %s: %w\", c.Field, err)\n\t\t\t\treturn result, result.Error\n\t\t\t}\n\t\t}\n\t\tresult.ConflictsResolved = true\n\n\t\t// CommitMergeResolution, not Commit: Commit's GH#3886 nothing-to-commit\n\t\t// tolerance would swallow the --ours case (resolution dirties nothing)\n\t\t// as a silent no-op here, leaving dolt_merge_status.is_merging true while\n\t\t// this function reports result.Merged = true and pushes — the exact\n\t\t// re-wedge CommitMergeResolution's doc comment describes. See the\n\t\t// server-mode twin, dolt/federation.go's Sync.\n\t\tif err := s.CommitMergeResolution(ctx, fmt.Sprintf(\"Resolve conflicts from %s using %s strategy\", peer, strategy)); err != nil {","sourceCodeStart":314,"sourceCodeEnd":350,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/embeddeddolt/federation.go#L314-L350","documentation":"When merging a peer branch produces conflicts and no resolution strategy was supplied, Sync stops and returns this error with result.Conflicts populated. The merge is left in a merging state; the caller must re-run sync with an explicit strategy (ours or theirs) to resolve.","triggerScenarios":"store.Sync(ctx, peer) called with strategy == \"\" while s.Merge returned non-empty conflicts — both peers edited the same issue field (e.g. title/status) since their last common commit.","commonSituations":"Two agents/machines updated the same bead offline, then both sync; automated sync jobs omitting the --strategy flag; first sync after long divergence between peers.","solutions":["Inspect result.Conflicts to see which fields conflict.","Re-run sync with --strategy ours to keep local values, or --strategy theirs to take the peer's values.","Reduce divergence by syncing more frequently so fewer fields conflict.","If the merge is left in-progress, resolve or abort it before other operations."],"exampleFix":"// before: conflicts, no strategy\nresult, err := store.Sync(ctx, peer)\n// after: supply a strategy\nresult, err := store.SyncWithStrategy(ctx, peer, \"ours\") // or \"theirs\"","handlingStrategy":"validation","validationCode":"// only auto-sync when either no conflicts are expected or a strategy is supplied\nfunc canSyncAutomatically(strategy string) bool {\n    return strategy == \"ours\" || strategy == \"theirs\"\n}\nif !canSyncAutomatically(strategy) {\n    return fmt.Errorf(\"refusing unattended sync without --strategy ours|theirs\")\n}","typeGuard":null,"tryCatchPattern":"result, err := store.Sync(ctx, peer)\nif err != nil && strings.Contains(err.Error(), \"merge conflicts require resolution\") {\n    // conflicts are in result.Conflicts; re-run with an explicit strategy\n    for _, c := range result.Conflicts {\n        log.Printf(\"conflict on field %q\", c.Field)\n    }\n    result, err = store.SyncWithStrategy(ctx, peer, chosenStrategy)\n}","preventionTips":["Always pass --strategy ours|theirs for unattended sync jobs.","Sync frequently so fewer fields diverge.","Review result.Conflicts after every conflicted sync.","Partition ownership of beads across peers to avoid same-field edits."],"tags":["merge-conflict","sync","dolt"],"backgroundTag":"merge-conflict-requires-resolution","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}