gastownhall/beads · error

iterate dirty config diff

Error message

iterate dirty config diff: %w

What it means

Wraps a rows-scanning error from a SQL query that diffs the config table to find dirty internal config keys before a pull. It is thrown because the library cannot determine which config keys are dirty, so it must abort the pre-pull auto-commit check rather than guess.

Solutions

  1. Check Dolt server health and connectivity (bd dolt status).
  2. Retry the pull once the connection is stable.
  3. Inspect the wrapped cause (%w) for the specific driver error and address it (e.g. table lock, schema mismatch).
  4. If schema-related, verify the beads database schema version matches your bd version.
Defensive patterns

Strategy: retry

Validate before calling

// before triggering pre-pull commit
if err := s.db.PingContext(ctx); err != nil {
    return fmt.Errorf("dolt database unreachable before pull: %w", err)
}

Try / catch

var iterateErr *storageError
if errors.As(err, &iterateErr) && isConnectionError(iterateErr) {
    // back off and retry the pull once connectivity is restored
}

Prevention

When it happens

Trigger: The config-diff query (iterating rows returned by a dolt diff/status-style query over config keys) fails mid-iteration — e.g. the underlying Dolt table query errored after some rows were read.

Common situations: Database connection drop during pull, Dolt server restart, schema/lock contention on the config table, or a corrupt working-set diff.

Related errors


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

Appendix: source

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

	rows, err := conn.QueryContext(ctx,
		"SELECT COALESCE(to_key, from_key) FROM dolt_diff('HEAD', 'WORKING', 'config')")
	if err != nil {
		return fmt.Errorf("inspect dirty config before pull: %w", err)
	}
	defer rows.Close()

	var unsafe []string
	for rows.Next() {
		var key sql.NullString
		if err := rows.Scan(&key); err != nil {
			return fmt.Errorf("scan dirty config key: %w", err)
		}
		if key.Valid && !strings.HasPrefix(key.String, kvkeys.Prefix) {
			unsafe = append(unsafe, key.String)
		}
	}
	if err := rows.Err(); err != nil {
		return fmt.Errorf("iterate dirty config diff: %w", err)
	}
	if len(unsafe) > 0 {
		return fmt.Errorf("refusing to auto-commit %d dirty internal config key(s) before pull: %s; "+
			"only user %s* keys auto-commit before a pull (GH#2455) — commit or revert "+
			"these explicitly with `bd dolt commit` first", len(unsafe), strings.Join(unsafe, ", "), kvkeys.Prefix)
	}
	return nil
}

// CommitWithConfig creates a Dolt commit that includes the config table.
// Use this instead of Commit when the caller intentionally modified config
// (e.g., CommitPending after 'bd config set', 'bd init', or 'bd rename-prefix').
// GH#2455: Commit() excludes config to prevent sweeping up stale changes.
func (s *DoltStore) CommitWithConfig(ctx context.Context, message string) error {
	return s.withCircuitWrite(ctx, func(ctx context.Context) error {
		conn, err := s.db.Conn(ctx)
		if err != nil {
			return fmt.Errorf("failed to acquire connection: %w", err)

View on GitHub (pinned to 71377f2769)