gastownhall/beads · error
failed to commit pending changes before pull: %w
Error message
failed to commit pending changes before pull: %w
What it means
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.
Source
Thrown at internal/storage/dolt/federation.go:85
// For git-protocol remotes, uses CLI `dolt pull` to avoid MySQL connection timeouts.
// Returns any merge conflicts if present.
func (s *DoltStore) PullFrom(ctx context.Context, peer string) ([]storage.Conflict, error) {
var conflicts []storage.Conflict
err := s.withCircuitWrite(ctx, func(ctx context.Context) error {
var err error
conflicts, err = s.pullFromPeer(ctx, peer)
return err
})
return conflicts, err
}
func (s *DoltStore) pullFromPeer(ctx context.Context, peer string) ([]storage.Conflict, error) {
// GH#2474: Auto-commit pending changes before pull to prevent
// "cannot merge with uncommitted changes" errors.
if !s.readOnly {
if err := s.commitBeforePull(ctx, "auto-commit before pull"); err != nil {
if !isDoltNothingToCommit(err) {
return nil, fmt.Errorf("failed to commit pending changes before pull: %w", err)
}
}
}
// bd-6dnrw.3: pre-pull HEAD for the post-merge is_blocked recompute; an
// unreadable HEAD degrades to a full recompute.
preHead := ""
if !s.readOnly {
if h, err := s.GetCurrentCommit(ctx); err == nil {
preHead = h
}
}
// bd-578h9.3: every peer-pull route funnels through the same settle
// machinery as the default-remote pull (pullTransport): the CLI routes
// through finishCLIPull, the SQL route through pullWithAutoResolve. A bare
// peer pull used to leave non-convergent merges behind — an FK
// delete-vs-insert divergence rolls the merge back with nothing inView on GitHub (pinned to 71377f2769)
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.
Example fix
// before: ambiguous dirty state blocks every pull // error: failed to commit pending changes before pull // after: commit explicitly before syncing dolt add -A && dolt commit -m "pre-pull auto-commit" // or discard unintended changes dolt checkout . // then retry the peer pull
Defensive patterns
Strategy: validation
Validate before calling
// Shell: ensure clean working set before peer pull
dolt status --porcelain | grep -q . && { echo "uncommitted changes; commit first"; exit 1; } Type guard
func IsPrePullCommitError(err error) bool {
return err != nil && strings.Contains(err.Error(), "failed to commit pending changes before pull")
} Try / catch
conflicts, err := sync.PullFromPeer(ctx, peer)
if err != nil && strings.Contains(err.Error(), "failed to commit pending changes before pull") {
// recover: commit or discard dirty state, then retry once
return sync.CommitAndRetryPull(ctx, peer)
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- failed to commit federation peer: %w
- failed to pull from peer %s: %w
- failed to commit pending changes before sync: %w
- merge failed: %w
- failed to commit conflict resolution: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/5bf5d98cacfb432a.
Report an issue: GitHub.