gastownhall/beads · error

dolt add %s: %w

Error message

dolt add %s: %w

What it means

StageAndCommit stages each dirty table with CALL DOLT_ADD(?) and wraps failures as 'dolt add <table>: %w'. Dolt rejects DOLT_ADD for tables that don't exist or names that can't be staged (e.g. dolt-ignored tables). Each failure aborts the remaining staging steps, so dirtyTables is processed in map (non-deterministic) order.

Source

Thrown at internal/storage/versioncontrolops/commit.go:76

	// — at high-frequency callers (config/metadata heartbeats, reconcile counters,
	// idempotent label/dependency writes) this floods the Dolt log.
	//
	// Cheap fast-path: if NOTHING is pending in the whole working set (excluding
	// dolt-ignored tables, which cannot be staged), skip without touching Dolt's
	// staging machinery. Note: callers like Update/Close also write an events row,
	// so a zero-rows main-table write can still be a real change — dolt_status
	// captures that correctly where a rows-affected check would not.
	pending, err := issueops.HasPendingChanges(ctx, conn)
	if err != nil {
		return fmt.Errorf("check pending changes before commit: %w", err)
	}
	if !pending {
		return nil
	}

	for table := range dirtyTables {
		if _, err := conn.ExecContext(ctx, "CALL DOLT_ADD(?)", table); err != nil {
			return fmt.Errorf("dolt add %s: %w", table, err)
		}
	}

	// Precise guard: HasPendingChanges above is global, but we only DOLT_ADD the
	// dirty-tracked tables. When those specific tables turn out clean (idempotent
	// no-op) while some UNRELATED table is concurrently dirty, the fast-path does
	// not fire yet staging stages nothing — so DOLT_COMMIT('-m') would still emit
	// the "nothing to commit" warning. Check the STAGED set (exactly what '-m'
	// will commit) and skip the empty commit.
	staged, err := issueops.HasStagedChanges(ctx, conn)
	if err != nil {
		return fmt.Errorf("check staged changes before commit: %w", err)
	}
	if !staged {
		return nil
	}
	if author == "" {
		_, err = conn.ExecContext(ctx, "CALL DOLT_COMMIT('-m', ?)", commitMsg)

View on GitHub (pinned to 71377f2769)

Solutions

  1. Verify each table in dirtyTables exists and is not dolt-ignored before staging
  2. Filter out stale entries from dirtyTables when tables were dropped/renamed
  3. Inspect the wrapped driver error for the specific table Dolt rejected and remove it from the tracked set

Example fix

// before
err := versioncontrolops.StageAndCommit(ctx, conn, map[string]bool{"issues": true, "dropped_tbl": true}, msg, "")
// after
tables := pruneNonexistentTables(ctx, conn, dirtyTables)
err := versioncontrolops.StageAndCommit(ctx, conn, tables, msg, "")
Defensive patterns

Strategy: validation

Validate before calling

for table := range dirtyTables {
    var n int
    if err := conn.QueryRowContext(ctx,
        "SELECT COUNT(*) FROM information_schema.tables WHERE table_name = ?", table).Scan(&n); err != nil || n == 0 {
        delete(dirtyTables, table) // drop stale/ignored entries before staging
    }
}

Prevention

When it happens

Trigger: Calling StageAndCommit with a dirtyTables entry naming a nonexistent or dolt-ignored table; DOLT_ADD failing due to connection issues; concurrent session mutating the staging area.

Common situations: Caller tracking a table that was since dropped or renamed; adding ignored/virtual tables; stale connections mid-commit; case-mismatched table names on case-sensitive servers.

Related errors


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