gastownhall/beads · error
failed to get rows affected: %w
Error message
failed to get rows affected: %w
What it means
After the claim UPDATE succeeds as SQL, ClaimIssueInTx calls result.RowsAffected() to decide whether the CAS won. If the driver cannot report the affected-row count, this error wraps that failure. It indicates a driver/driver-backend limitation rather than a claim conflict.
Source
Thrown at internal/storage/issueops/claim.go:134
SET assignee = ?, status = 'in_progress', updated_at = ?, started_at = ?, %s
WHERE id = ? AND row_lock = ? AND status IN (%s)
`, issueTable, rowLockClause, statusPlaceholders), args...)
} else {
args := append([]interface{}{actor, now}, rowLockArgs...)
args = append(args, id, oldIssue.RowVersion)
args = append(args, statusArgs...)
result, err = tx.ExecContext(ctx, fmt.Sprintf(`
UPDATE %s
SET assignee = ?, status = 'in_progress', updated_at = ?, %s
WHERE id = ? AND row_lock = ? AND status IN (%s)
`, issueTable, rowLockClause, statusPlaceholders), args...)
}
if err != nil {
return nil, fmt.Errorf("failed to claim issue: %w", err)
}
rowsAffected, err = result.RowsAffected()
if err != nil {
return nil, fmt.Errorf("failed to get rows affected: %w", err)
}
}
if rowsAffected == 0 {
assignee, currentStatus, err := readClaimStateInTx(ctx, tx, issueTable, id)
if err != nil {
return nil, fmt.Errorf("failed to get current claim state: %w", err)
}
// Idempotent: if already claimed in_progress by the same actor —
// including a spelling difference across layers (ga-wzl83) — treat as
// success. This supports agent retry workflows where claim may be
// called multiple times after transient failures (GH#8).
if actorMatches(assignee, actor) && currentStatus == types.StatusInProgress {
return &ClaimResult{OldIssue: oldIssue, IsWisp: isWisp}, nil
}
// The refusal carries the state that lost the CAS, read just above in
// THIS transaction, so a caller learns who won without parsing the
// message. The typed wrapper carries the fields; the PROSE is composedView on GitHub (pinned to 71377f2769)
Solutions
- Re-run the claim; a same-actor in_progress re-claim is idempotent
- Verify the storage driver is the supported dolthub/driver path, not a shim
- Check connection stability to the database server
Defensive patterns
Strategy: retry
Validate before calling
// use the supported dolthub driver, not a shim; verify with bd doctor // no pre-call check can detect RowsAffected support; treat as infra health issue
Try / catch
if err != nil && strings.Contains(err.Error(), "failed to get rows affected") {
return retryClaim(ctx, id, actor) // claim CAS is idempotent for same actor
} Prevention
- Stick to the supported storage driver (dolthub/driver) for the Dolt backend
- Avoid poolers/proxies that strip result metadata between exec and stat
- Retry once on this error before surfacing it — state is unchanged
When it happens
Trigger: tx.ExecContext succeeded but result.RowsAffected() returned an error on the CAS UPDATE in ClaimIssueInTx — typically with drivers or proxy setups that don't implement RowsAffected, or a connection that dropped between exec and stat.
Common situations: Using a non-standard SQL driver or connection pooler in front of Dolt that doesn't propagate affected-row metadata; flaky connection dying between ExecContext and RowsAffected.
Related errors
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/b2b9634f65767707.
Report an issue: GitHub.