gastownhall/beads · warning

dolt commit: %w

Error message

dolt commit: %w

What it means

commitAllInTx ran `CALL DOLT_COMMIT('-Am', ?)` and Dolt reported there is nothing to commit (the working set matches HEAD). Because tolerateEmpty was false, the caller explicitly wanted an error for empty commits, so the NothingToCommit error is wrapped and returned as `dolt commit: %w`. When the error is NOT nothing-to-commit, it is instead routed to wrapCommitIndeterminate — this specific error means a clean, known-empty commit.

Source

Thrown at internal/storage/embeddeddolt/version_control.go:140

// CommitAll commits the entire working set (config included) with the given
// message and reports whether a commit actually landed — the
// storage.VersionControl entry point for the explicit operator commands
// (bd vc commit, bd dolt commit). Embedded commits already stage everything
// via DOLT_COMMIT('-Am'); what the explicit commands need from this store is
// the committed bool, which replaces their HEAD-before/HEAD-after comparison
// (racy against concurrent writers, and two extra engine opens per call —
// the same reasoning as CommitPending's doc comment).
func (s *EmbeddedDoltStore) CommitAll(ctx context.Context, message string) (bool, error) {
	return s.commitAll(ctx, message, true)
}

func commitAllInTx(ctx context.Context, tx *sql.Tx, message string, tolerateEmpty bool) (bool, error) {
	if _, err := tx.ExecContext(ctx, "CALL DOLT_COMMIT('-Am', ?)", message); err != nil {
		if issueops.IsNothingToCommitError(err) {
			if tolerateEmpty {
				return false, nil
			}
			return false, fmt.Errorf("dolt commit: %w", err)
		}
		return false, wrapCommitIndeterminate("dolt commit", err)
	}
	return true, nil
}

// stageAndCommitAfterSQLCommit preserves the no-replay boundary for version
// publication after an already-visible SQL mutation.
func stageAndCommitAfterSQLCommit(ctx context.Context, db versioncontrolops.DBConn, dirtyTables map[string]bool, commitMsg, author string) error {
	if err := versioncontrolops.StageAndCommit(ctx, db, dirtyTables, commitMsg, author); err != nil {
		return wrapCommitIndeterminate("embeddeddolt: stage and commit after SQL commit", err)
	}
	return nil
}

// Commit stages and commits the full working set. A clean working set is not
// an error here: the server store (DoltStore.Commit et al., via
// isDoltNothingToCommit) has always tolerated Dolt's "nothing to commit"

View on GitHub (pinned to 71377f2769)

Solutions

  1. This is usually benign: check the wrapped error for the nothing-to-commit signature (issueops.IsNothingToCommitError) and treat it as a no-op.
  2. Pass tolerateEmpty=true when an empty working set is acceptable, so commitAllInTx returns (false, nil) instead of erroring.
  3. Remove redundant commit calls — verify pending changes exist (dirty tracker / dolt status equivalent) before committing.
  4. If you expected changes to exist, inspect why the working set is empty: the earlier commit may have already succeeded (possibly indeterminately — check for storage.ErrCommitIndeterminate upstream).

Example fix

// before: erroring on empty commit
committed, err := commitAllInTx(ctx, tx, msg, false)

// after: tolerate empty when it is expected
committed, err := commitAllInTx(ctx, tx, msg, true)
if err == nil && !committed {
    // nothing to commit — fine
}
Defensive patterns

Strategy: validation

Validate before calling

// check for pending changes before requesting a strict commit
// (e.g. via a status/dirty API)
if !store.HasPendingChanges(ctx) {
    return nil // nothing to commit; skip the strict commit
}

Try / catch

if err := commitStrict(ctx); err != nil {
    if isNothingToCommit(err) { // issueops.IsNothingToCommitError signature
        return nil // benign: working set already clean
    }
    return err
}

Prevention

When it happens

Trigger: Calling commitAllInTx (directly or via CommitPending / runTransactionWithMessage paths) with tolerateEmpty=false on a database whose working set has no changes — e.g. committing pending changes when none exist, or double-committing after a prior successful commit.

Common situations: Running a pull/merge flow that pre-commits pending changes when everything is already committed; calling commit twice in one command; tests asserting that empty commits surface as errors rather than no-ops.

Related errors


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