gastownhall/beads · error
failed to commit pending changes before sync: %w
Error message
failed to commit pending changes before sync: %w
What it means
Before pulling, Sync auto-commits any dirty working-set changes (e.g. federation metadata like add-peer plus persistent memories, which plain Commit excludes per GH#2455) so DOLT_MERGE cannot wedge with 'cannot merge with uncommitted changes'. This error means that pre-sync commit itself failed for a reason other than 'nothing to commit'.
Source
Thrown at internal/storage/dolt/federation.go:357
// 2. Merge peer's changes (handling conflicts per strategy)
// 3. Push local changes to peer
//
// Returns the sync result including any conflicts encountered.
func (s *DoltStore) Sync(ctx context.Context, peer string, strategy string) (*SyncResult, error) {
result := &SyncResult{
Peer: peer,
StartTime: time.Now(),
}
// GH#2474: match PullFrom — commit pending changes before the merge,
// INCLUDING config (where kv.memory.* rows live). Plain Commit excludes
// config (GH#2455), so federation metadata writes such as add-peer plus any
// persistent memories would otherwise leave the working set dirty and wedge
// DOLT_MERGE ("cannot merge with uncommitted changes").
if !s.readOnly {
if err := s.commitBeforePull(ctx, "auto-commit before sync"); err != nil {
if !isDoltNothingToCommit(err) {
result.Error = fmt.Errorf("failed to commit pending changes before sync: %w", err)
return result, result.Error
}
}
}
// Step 1: Fetch from peer
if err := s.Fetch(ctx, peer); err != nil {
result.Error = fmt.Errorf("fetch failed: %w", err)
return result, result.Error
}
result.Fetched = true
// Step 2: Get status before merge
beforeCommit, _ := s.GetCurrentCommit(ctx) // Best effort: empty commit hash means diff won't be logged
// Step 3: Merge peer's branch
remoteBranch := fmt.Sprintf("%s/%s", peer, s.branch)
conflicts, err := s.Merge(ctx, remoteBranch)View on GitHub (pinned to 71377f2769)
Solutions
- Inspect the wrapped cause to see why the commit failed
- Check for and clear stale dolt locks or concurrent `bd sync` processes (ps / dolt_admin status)
- Run the sync again after resolving contention — the auto-commit retriggers
- If a prior crashed sync left the working set wedged, inspect `dolt status` and commit or discard changes manually
- Ensure the dolt sql-server is healthy and the database directory is writable/non-full
Example fix
// before: blind retry loop
for { store.Sync(ctx, peer, "", nil) }
// after: single-flight sync guard
syncMu.Lock()
defer syncMu.Unlock()
_, err := store.Sync(ctx, peer, "", nil) // auto-commit no longer races Defensive patterns
Strategy: validation
Validate before calling
// ensure clean, uncontended working set before Sync
if anotherSyncRunning() { return ErrSyncBusy }
_ = store.Commit(ctx, "pre-sync checkpoint") // best-effort commit outside readOnly Try / catch
result, err := store.Sync(ctx, peer, strategy, opts)
if err != nil && strings.Contains(err.Error(), "commit pending changes before sync") {
// clear contention, then retry once
releaseLocks(); retrySync()
} Prevention
- Single-flight all syncs with a mutex or lock file
- Always commit or checkpoint before invoking Sync
- Keep disk space and dolt server health monitored
- After a crash, inspect `dolt status` before resuming syncs
When it happens
Trigger: Sync(ctx, peer, ...) on a writable store calls commitBeforePull(ctx, "auto-commit before sync") and receives a real commit error (SQL failure, lock contention, hook failure) that is not isDoltNothingToCommit.
Common situations: Another process holds the dolt working set or server lock; dirty state from a prior crashed sync; disk-full or DB connection drop mid-commit; concurrent syncs racing on the same database.
Related errors
- failed to commit conflict resolution: %w
- failed to commit federation peer: %w
- failed to commit pending changes before pull: %w
- fetch failed: %w
- merge failed: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/e0f23187fb301162.
Report an issue: GitHub.