gastownhall/beads · error

db: Claim %s: rows affected: %w

Error message

db: Claim %s: rows affected: %w

What it means

This error wraps a failure of res.RowsAffected() after the claim UPDATE executed. If the driver cannot report the affected-row count, Claim cannot tell whether the CAS succeeded and aborts with this wrapped error.

Source

Thrown at internal/storage/domain/db/issue.go:489

				WHERE id = ? AND row_lock = ? AND (%s)
			`, table, rowLockClause, statusPredicate), args...)
		} else {
			args := append([]any{actor, now}, rowLockArgs...)
			args = append(args, id, oldIssue.RowVersion)
			args = append(args, statusArgs...)
			//nolint:gosec // G201: table is one of two hardcoded constants
			res, err = r.runner.ExecContext(ctx, fmt.Sprintf(`
				UPDATE %s
				SET assignee = ?, status = 'in_progress', updated_at = ?, %s
				WHERE id = ? AND row_lock = ? AND (%s)
			`, table, rowLockClause, statusPredicate), args...)
		}
		if err != nil {
			return domain.ClaimRowResult{}, fmt.Errorf("db: Claim %s: %w", id, err)
		}
		rows, err = res.RowsAffected()
		if err != nil {
			return domain.ClaimRowResult{}, fmt.Errorf("db: Claim %s: rows affected: %w", id, err)
		}
	}

	if rows == 0 {
		var currentAssignee sql.NullString
		var currentStatus types.Status
		//nolint:gosec // G201: table is one of two hardcoded constants
		if err := r.runner.QueryRowContext(ctx,
			fmt.Sprintf("SELECT assignee, status FROM %s WHERE id = ?", table), id,
		).Scan(&currentAssignee, &currentStatus); err != nil {
			return domain.ClaimRowResult{}, fmt.Errorf("db: Claim %s: read current state: %w", id, err)
		}
		assignee := ""
		if currentAssignee.Valid {
			assignee = currentAssignee.String
		}
		return domain.ClaimRowResult{
			Updated:               false,

View on GitHub (pinned to 71377f2769)

Solutions

  1. Retry the claim — the transaction rolled back so the CAS can be re-run cleanly.
  2. Check network/driver stability between client and database server.
  3. Verify the driver version supports RowsAffected for UPDATE statements.
  4. Inspect the wrapped cause for connection-reset signatures and reconnect.

Example fix

// before
res, err := store.Claim(ctx, id, actor, opts) // opaque RowsAffected failure
// after
if err != nil {
    var netErr net.Error
    if errors.As(err, &netErr) { res, err = store.Claim(ctx, id, actor, opts) }
}
Defensive patterns

Strategy: retry

Validate before calling

if err := pingStore(ctx); err != nil { return fmt.Errorf("store unreachable: %w", err) }

Try / catch

res, err := store.Claim(ctx, id, actor, opts)
if err != nil && errors.Is(err, driver.ErrBadConn) {
    res, err = store.Claim(ctx, id, actor, opts) // rolled-back tx, safe retry
}

Prevention

When it happens

Trigger: Calling Claim with a driver/connection where RowsAffected errors after the UPDATE: broken connection returned with the result, driver limitation, or mid-statement connection teardown.

Common situations: Unstable network to a remote Dolt server; driver quirks where RowsAffected errors despite successful execution; pooled connections invalidated server-side.

Related errors


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