{"record":{"id":"5bf5d98cacfb432a","repo":"gastownhall/beads","slug":"failed-to-commit-pending-changes-before-pull-w","errorCode":null,"errorMessage":"failed to commit pending changes before pull: %w","messagePattern":"failed to commit pending changes before pull: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/dolt/federation.go","lineNumber":85,"sourceCode":"// For git-protocol remotes, uses CLI `dolt pull` to avoid MySQL connection timeouts.\n// Returns any merge conflicts if present.\nfunc (s *DoltStore) PullFrom(ctx context.Context, peer string) ([]storage.Conflict, error) {\n\tvar conflicts []storage.Conflict\n\terr := s.withCircuitWrite(ctx, func(ctx context.Context) error {\n\t\tvar err error\n\t\tconflicts, err = s.pullFromPeer(ctx, peer)\n\t\treturn err\n\t})\n\treturn conflicts, err\n}\n\nfunc (s *DoltStore) pullFromPeer(ctx context.Context, peer string) ([]storage.Conflict, error) {\n\t// GH#2474: Auto-commit pending changes before pull to prevent\n\t// \"cannot merge with uncommitted changes\" errors.\n\tif !s.readOnly {\n\t\tif err := s.commitBeforePull(ctx, \"auto-commit before pull\"); err != nil {\n\t\t\tif !isDoltNothingToCommit(err) {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to commit pending changes before pull: %w\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\t// bd-6dnrw.3: pre-pull HEAD for the post-merge is_blocked recompute; an\n\t// unreadable HEAD degrades to a full recompute.\n\tpreHead := \"\"\n\tif !s.readOnly {\n\t\tif h, err := s.GetCurrentCommit(ctx); err == nil {\n\t\t\tpreHead = h\n\t\t}\n\t}\n\n\t// bd-578h9.3: every peer-pull route funnels through the same settle\n\t// machinery as the default-remote pull (pullTransport): the CLI routes\n\t// through finishCLIPull, the SQL route through pullWithAutoResolve. A bare\n\t// peer pull used to leave non-convergent merges behind — an FK\n\t// delete-vs-insert divergence rolls the merge back with nothing in","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dolt/federation.go#L67-L103","documentation":"pullFromPeer tries to auto-commit any pending uncommitted changes before merging from a peer (GH#2474) because Dolt refuses to merge with a dirty working set. If commitBeforePull fails with something other than 'nothing to commit' (isDoltNothingToCommit), the pull aborts with this wrapped error. It signals the local working set couldn't be safely committed, so the merge was not attempted.","triggerScenarios":"Calling pullFromPeer (peer sync flows) with s.readOnly == false while the Dolt working set has changes that commitBeforePull cannot commit — e.g. merge conflicts during the auto-commit, a locked/failed Dolt transaction, or an exec failure in the commit step that isn't a nothing-to-commit condition.","commonSituations":"Two bd processes writing concurrently so the working set changes between check and commit; a Dolt server error (lock timeout, disk full) blocks the auto-commit; database left in a dirty state by a previously crashed operation.","solutions":["Inspect the innermost error: if it's a lock/timeout issue, stop other bd processes and retry the pull.","Run `dolt status` (or bd doctor) to see what's uncommitted; resolve or discard the dirty state manually, then retry.","If the auto-commit itself conflicts, commit or stash the changes deliberately before pulling.","Free disk space / restart the Dolt server if the commit failed on resource or server errors, then re-run the sync."],"exampleFix":"// before: ambiguous dirty state blocks every pull\n// error: failed to commit pending changes before pull\n// after: commit explicitly before syncing\ndolt add -A && dolt commit -m \"pre-pull auto-commit\"\n// or discard unintended changes\ndolt checkout .\n// then retry the peer pull","handlingStrategy":"validation","validationCode":"// Shell: ensure clean working set before peer pull\ndolt status --porcelain | grep -q . && { echo \"uncommitted changes; commit first\"; exit 1; }","typeGuard":"func IsPrePullCommitError(err error) bool {\n\treturn err != nil && strings.Contains(err.Error(), \"failed to commit pending changes before pull\")\n}","tryCatchPattern":"conflicts, err := sync.PullFromPeer(ctx, peer)\nif err != nil && strings.Contains(err.Error(), \"failed to commit pending changes before pull\") {\n\t// recover: commit or discard dirty state, then retry once\n\treturn sync.CommitAndRetryPull(ctx, peer)\n}","preventionTips":["Avoid concurrent bd writers so the working set stays clean at sync time.","Run `dolt status` before scheduled pulls; auto-commit or clean beforehand.","After any crashed operation, check for leftover dirty state before syncing.","Ensure adequate disk space; commit failures on full disks leave the tree dirty and block pulls."],"tags":["dolt","federation","pull","merge","commit"],"backgroundTag":"merge-uncommitted-changes","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}