gastownhall/beads · error
get rows affected: %w
Error message
get rows affected: %w
What it means
deleteIssueRowInTx wraps a failure of result.RowsAffected() after the DELETE statement succeeded. This is rare: it means the driver could not report how many rows the statement removed (some drivers/pooled connections can't provide rows-affected). It precedes the not-found check.
Source
Thrown at internal/storage/issueops/delete.go:62
}
if err := RecomputeIsBlockedInTx(ctx, tx, affectedIssues, affectedWisps); err != nil {
return fmt.Errorf("recompute is_blocked after delete for %s: %w", id, err)
}
return nil
}
//nolint:gosec // G201: table names come from WispTableRouting (hardcoded constants)
func deleteIssueRowInTx(ctx context.Context, tx *sql.Tx, id string, isWisp bool) error {
issueTable, _, _, _ := WispTableRouting(isWisp)
result, err := tx.ExecContext(ctx, fmt.Sprintf("DELETE FROM %s WHERE id = ?", issueTable), id)
if err != nil {
return fmt.Errorf("delete issue from %s: %w", issueTable, err)
}
rows, err := result.RowsAffected()
if err != nil {
return fmt.Errorf("get rows affected: %w", err)
}
if rows == 0 {
// Wrap the sentinel so callers can errors.Is(..., storage.ErrNotFound),
// matching GetIssue/UpdateIssue. The storage conformance suite asserts
// this parity across not-found paths.
return fmt.Errorf("%w: issue %s", storage.ErrNotFound, id)
}
// Journal the delete in the same transaction. This worker backs single
// deletes (DeleteIssueInTx) and the per-wisp branch of the bulk delete
// (DeleteResolvedSetInTx); the bulk regular-issue branch journals its own
// ids directly. The rows==0 return above is what keeps this
// actually-deleted-only. The delete plumbing (storage.DeleteIssue and the
// bulk/cascade resolvers) carries no actor, so the row records none.
if err := RecordDeleteInTx(ctx, tx, id, ""); err != nil {
return err
}
if isWisp {
if err := DeleteWispFromDependenciesInTx(ctx, tx, id); err != nil {View on GitHub (pinned to 71377f2769)
Solutions
- Inspect the wrapped error; it is a driver result-metadata failure.
- Upgrade the dolthub/driver dependency to a current version.
- Retry the delete in a fresh transaction/connection.
- If reproducible, report to the driver: the DELETE succeeded, only the affected-count read failed.
Defensive patterns
Strategy: fallback
Try / catch
if err := storage.DeleteIssue(ctx, db, id); err != nil {
if isResultMetadataErr(err) { // RowsAffected failed after a successful DELETE
// verify outcome by re-reading the row, then proceed or retry
}
return err
} Prevention
- Keep the dolthub/driver dependency up to date.
- Re-verify row existence after this error before assuming the delete failed.
- Report persistent occurrences to the driver project.
When it happens
Trigger: Calling any delete path when the database/driver's RowsAffected call errors after a successful DELETE — driver-level result metadata failure, very old or mismatched driver version.
Common situations: Mismatched or outdated Dolt SQL driver version that doesn't fully implement result metadata; connection in a degraded state where the result handle is invalid.
Related errors
- failed to check rows affected for issue counter prefix %q: %
- failed to check rows affected after seeding for prefix %q: %
- getting issue %s: %w
- failed to open long-timeout connection: %w
- failed to open migration connection: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/71c4c35591c6a502.
Report an issue: GitHub.