gastownhall/beads · error

failed to stage %s before commit: %w

Error message

failed to stage %s before commit: %w

What it means

Once dirty tables are discovered, each is staged with CALL DOLT_ADD(?) via schema.DrainCall before DOLT_COMMIT runs. This error wraps a failure of that stored-procedure call for a specific table (the %s names it). The commit did not complete; the failure happened mid-staging, so the Dolt working set may have some tables staged.

Source

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

	}

	if len(tables) == 0 {
		// A merge resolution with a clean working set is NOT a no-op: it is
		// the `--ours` case, where our values already stood and resolving the
		// conflict dirtied nothing. Returning here left is_merging true while
		// the caller reported "Merge committed", and the next pull re-wedged
		// on the unconcluded merge (wy-36ilm, caught by the F9 integration
		// test). Only the merge-conclusion mode takes this path: for the
		// other modes an empty working set really is nothing to commit.
		if mode == configIncludeAll {
			return s.concludeOpenMerge(ctx, conn, message)
		}
		return nil // Nothing to commit (all changes were config-only or dolt_ignore'd)
	}

	for _, table := range tables {
		if err := schema.DrainCall(ctx, conn, "CALL DOLT_ADD(?)", table); err != nil {
			return fmt.Errorf("failed to stage %s before commit: %w", table, err)
		}
	}

	// NOTE: In SQL procedure mode, Dolt defaults author to the authenticated SQL user
	// (e.g. root@localhost). Always pass an explicit author for deterministic history.
	if err := schema.DrainCall(ctx, conn, "CALL DOLT_COMMIT('-m', ?, '--author', ?)", message, s.commitAuthorString()); err != nil {
		if isDoltNothingToCommit(err) {
			return nil
		}
		return s.wrapDoltPublicationFailure(ctx, "failed to commit", err)
	}

	return nil
}

// commitWorkingSetAfterSQLCommit preserves the no-replay boundary for a Dolt
// publication that follows an already-visible SQL mutation. commitWorkingSet
// classifies DOLT_COMMIT response loss itself; this wrapper adds the same

View on GitHub (pinned to 71377f2769)

Solutions

  1. Re-run the commit; dolt_status is re-queried so the stale table drops out of the staging list.
  2. Check for concurrent bd processes/sync jobs operating on the same repo and serialize them (file lock or single writer).
  3. Verify the named table still exists (SHOW TABLES) and is not blocked by a dolt_ignore rule.
  4. If DOLT_ADD keeps failing, inspect Dolt session state (dolt_status in a SQL shell) and retry on a fresh connection.
Defensive patterns

Strategy: retry

Validate before calling

// confirm the repo is quiescent before committing
// e.g. acquire your own single-writer lock; verify table exists:
// SHOW TABLES LIKE '<table>'

Try / catch

err := store.Commit(ctx, msg)
if err != nil && strings.Contains(err.Error(), "failed to stage") {
	// safe to re-run: dolt_status is re-queried next attempt
	time.Sleep(time.Second); return store.Commit(ctx, msg)
}

Prevention

When it happens

Trigger: DOLT_ADD fails for one table: the table was dropped/renamed between discovery and staging, a dolt_ignore rule conflicts, the session hit an error from a prior call, or the procedure returned an error row that DrainCall surfaces.

Common situations: Concurrent operations (another bd process committing/checking out) changing table presence mid-commit; GH#2455-style races with stale config rows; schema migrations removing tables while a commit is in flight.

Related errors


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