gastownhall/beads · error

failed to commit pending changes before pull: %w

Error message

failed to commit pending changes before pull: %w

What it means

DoltStore auto-commits any pending working-set changes before running a pull, because a merge cannot proceed with uncommitted changes. This error wraps whatever failure occurred during that pre-pull commit, excluding the benign 'nothing to commit' case. It means the store could not get its working set clean before the merge, so the pull was aborted.

Source

Thrown at internal/storage/dolt/store.go:3985

func (s *DoltStore) pullFromRemoteUnchecked(ctx context.Context, remote string) (retErr error) {
	ctx, span := doltTracer.Start(ctx, "dolt.pull",
		trace.WithSpanKind(trace.SpanKindClient),
		trace.WithAttributes(append(s.doltSpanAttrs(),
			attribute.String("dolt.remote", remote),
			attribute.String("dolt.branch", s.branch),
		)...),
	)
	defer func() { endSpan(span, retErr) }()

	// GH#2474: Auto-commit pending changes before pull to prevent
	// "cannot merge with uncommitted changes" errors. Store initialization
	// (schema init, molecule loading, metadata writes) can dirty the working
	// set before the user's pull command runs.
	if !s.readOnly {
		if err := s.commitBeforePull(ctx, "auto-commit before pull"); err != nil {
			// "nothing to commit" is fine — working set is already clean
			if !isDoltNothingToCommit(err) {
				return fmt.Errorf("failed to commit pending changes before pull: %w", err)
			}
		}
	}

	// bd-6dnrw.3: capture the pre-pull commit of the branch this store reads so a
	// successful merge can recompute the denormalized is_blocked column for the
	// rows it changed. Read before the transport; an unreadable head degrades to
	// a full recompute.
	//
	// ga-ivaps Finding 3: read this unconditionally, including for read-only
	// stores. verifyPullLanded's cheap fast path — a head that moved is proof the
	// transport landed — needs it, and without it every pull that DID merge
	// something pays a network DOLT_FETCH round trip it could have skipped. (A
	// no-op pull moves no head and refreshes the tracking ref regardless, so the
	// saved round trip is on the merged pulls, never the no-op ones.)
	// recomputeBlockedAfterPull below still runs only for writable stores.
	//
	// ga-ivaps Finding 1 (attempt 2): read the tip of s.branch, not the session

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the wrapped cause (%w) to identify the actual commit failure (timeout, lock, I/O).
  2. Re-run the pull — most causes (transient timeouts, lock contention) are temporary.
  3. Check that no other process/CLI is holding the Dolt database or working set lock.
  4. Verify the database server is reachable and the disk is not full.
  5. Run `bd doctor` / inspect dolt_status to see what rows are dirty and why.

Example fix

// before
err := store.Pull(ctx)
// after
if err != nil && strings.Contains(err.Error(), "failed to commit pending changes before pull") {
    time.Sleep(retryDelay) // transient lock/timeout cause
    err = store.Pull(ctx)
}
Defensive patterns

Strategy: retry

Validate before calling

if writable, err := store.CanCommit(ctx); err != nil { /* resolve dirty state before pulling */ }

Try / catch

if err := store.Pull(ctx); err != nil {
    if strings.Contains(err.Error(), "failed to commit pending changes before pull") {
        // inspect wrapped cause; wait and retry once
        time.Sleep(time.Second)
        err = store.Pull(ctx)
    }
    return err
}

Prevention

When it happens

Trigger: Calling Pull()/PullRemote() on a writable store whose working set is dirty (store init writes schema/molecule/metadata rows) and where the commit fails for a real reason: storage I/O failure, lock contention, context cancellation, or a Dolt commit error that is not 'nothing to commit'.

Common situations: Another process holds the Dolt database lock; the sql-server connection dropped mid-commit; disk full; a corrupted working set from a prior crashed merge; calling pull from a store that just wrote metadata and hit a transient MySQL timeout.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/f685d29d824771fb. Report an issue: GitHub.