gastownhall/beads · error

delete config %s: %w

Error message

delete config %s: %w

What it means

DeleteConfigInTx wraps the ExecContext error from deleting a row in the config table with this message, including the key being deleted. It means the DELETE statement itself failed — not that the key was missing (a missing key deletes zero rows without error).

Source

Thrown at internal/storage/issueops/bulk_ops.go:96

	for wispRows.Next() {
		var id string
		if err := wispRows.Scan(&id); err != nil {
			return nil, fmt.Errorf("scan wisp issue id: %w", err)
		}
		ids = append(ids, id)
	}
	if err := wispRows.Err(); err != nil {
		return nil, fmt.Errorf("iterate wisp issues by label: %w", err)
	}

	return ids, nil
}

// DeleteConfigInTx removes a configuration value.
func DeleteConfigInTx(ctx context.Context, tx *sql.Tx, key string) error {
	_, err := tx.ExecContext(ctx, "DELETE FROM config WHERE `key` = ?", key)
	if err != nil {
		return fmt.Errorf("delete config %s: %w", key, err)
	}
	return nil
}

// GetCommentsForIssuesInTx retrieves comments for multiple issues, partitioning
// between comments and wisp_comments tables.
//
//nolint:gosec // G201: table is hardcoded
func GetCommentsForIssuesInTx(ctx context.Context, tx *sql.Tx, issueIDs []string) (map[string][]*types.Comment, error) {
	if len(issueIDs) == 0 {
		return make(map[string][]*types.Comment), nil
	}

	result := make(map[string][]*types.Comment)

	// Partition IDs by wisp status in a single batched query, to avoid N
	// round-trips on remote backends (GH#3414).
	wispIDs, permIDs, err := PartitionWispIDsInTx(ctx, tx, issueIDs)

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped driver error; fix the underlying cause (connectivity, schema, locking) and retry the transaction.
  2. Extend or fix the context deadline if the delete was cancelled by timeout.
  3. Verify the config table exists and matches the expected schema (run bd doctor / migrations) if the error indicates a SQL/schema problem.

Example fix

// before
err := issueops.DeleteConfigInTx(ctx, tx, "my.key")
// after
if err := issueops.DeleteConfigInTx(ctx, tx, "my.key"); err != nil {
    if errors.Is(ctx.Err(), context.DeadlineExceeded) {
        ctx, cancel = context.WithTimeout(context.Background(), 30*time.Second)
        defer cancel()
        err = retryTx(ctx, func(tx *sql.Tx) error { return issueops.DeleteConfigInTx(ctx, tx, "my.key") })
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

func canDeleteConfig(ctx context.Context, tx *sql.Tx) error {
    if ctx.Err() != nil { return ctx.Err() }
    var n int
    return tx.QueryRowContext(ctx, "SELECT COUNT(*) FROM config").Scan(&n)
}

Try / catch

if err := issueops.DeleteConfigInTx(ctx, tx, key); err != nil {
    var base error
    errors.As(err, &base) // inspect wrapped driver error
    return fmt.Errorf("config delete aborted, retry whole tx: %w", err)
}

Prevention

When it happens

Trigger: tx.ExecContext("DELETE FROM config WHERE `key` = ?") fails: connection loss, context cancellation, SQL syntax/schema errors, table locked, or read-only transaction.

Common situations: Dolt server unavailable mid-transaction; schema drift where the config table is missing; context deadline expiring during the delete; embedded database file locked by another process.

Related errors


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