{"record":{"id":"1a6b53cea84a8662","repo":"gastownhall/beads","slug":"merge-failed-w-1a6b53","errorCode":null,"errorMessage":"merge failed: %w","messagePattern":"merge failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/embeddeddolt/federation.go","lineNumber":323,"sourceCode":"\t\tresult.Error = fmt.Errorf(\"commit pending before sync: %w\", err)\n\t\treturn result, result.Error\n\t}\n\n\t// Step 1: Fetch\n\tif err := s.Fetch(ctx, peer); err != nil {\n\t\tresult.Error = fmt.Errorf(\"fetch failed: %w\", err)\n\t\treturn result, result.Error\n\t}\n\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}","sourceCodeStart":305,"sourceCodeEnd":341,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/embeddeddolt/federation.go#L305-L341","documentation":"After a successful fetch, Sync merges the peer's branch (<peer>/<branch>). Any error from s.Merge(ctx, remoteBranch) is wrapped as 'merge failed', aborting before conflict handling. This is a hard merge failure, not a conflict outcome.","triggerScenarios":"store.Sync(ctx, peer) where s.Merge errors on merging remoteBranch: Dolt merge engine failure, divergent histories that Dolt cannot merge, corrupt objects fetched from the peer, or an internal dolt_schemas conflict.","commonSituations":"Peers rewrote history (force-push) making histories unrelated; fetched refs corrupted over an unreliable transport; storage-level failure during merge.","solutions":["Re-run sync after a fresh fetch to rule out a corrupted transfer.","If histories diverged (force-push), decide on one side: reset to a common ancestor or recreate the peer branch.","Inspect dolt_merge_status and merge logs for the concrete underlying error.","Use explicit strategy resolution (--strategy ours|theirs) if the failure is conflict-related underneath."],"exampleFix":"// before: force-pushed peer -> unrelated histories -> merge failed\nresult, err := store.Sync(ctx, peer)\n// after: verify shared history before merging\nif !historiesShareAncestor(localCommit, peerCommit) {\n    return fmt.Errorf(\"peer %s rewrote history; reconcile branches first\", peer)\n}\nresult, err = store.Sync(ctx, peer)","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"result, err := store.Sync(ctx, peer)\nif err != nil && strings.Contains(err.Error(), \"merge failed\") {\n    // surface underlying dolt_merge_status detail and stop automerge\n    log.Printf(\"merge with %s failed; manual reconciliation required: %v\", peer, err)\n    disableAutomerge(peer)\n}","preventionTips":["Never force-push shared federation branches.","Fetch and inspect peer state before merging large divergences.","Keep syncs frequent to limit divergence.","Watch dolt_merge_status after failed merges."],"tags":["merge","sync","dolt"],"backgroundTag":"merge-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}