gastownhall/beads · error
events since cursor (%v, %q) issue %q: %w
Error message
events since cursor (%v, %q) issue %q: %w
What it means
EventsSinceInTx queries events newer than a (createdAt, id) cursor, optionally filtered by issue ID, inside an existing transaction. This error wraps a low-level SQL failure from tx.QueryContext, so it means the events SELECT itself failed — not that no events were found. The cursor and issue ID are echoed into the message to make the failing query reproducible.
Source
Thrown at internal/storage/issueops/events.go:107
// Scope is the durable `events` table only — wisp_events are deliberately not
// unioned in, unlike GetAllEventsSince, so the feed stays durable-only.
func EventsSinceInTx(ctx context.Context, tx DBTX, cursorCreatedAt time.Time, cursorID, issueID string, limit int) ([]*types.Event, error) {
if limit <= 0 {
limit = defaultEventsSinceLimit
}
if limit > maxEventsSinceLimit {
limit = maxEventsSinceLimit
}
query := EventsSinceQuery(issueID, limit)
args := []any{cursorCreatedAt, cursorCreatedAt, cursorID}
if issueID != "" {
args = append(args, issueID)
}
rows, err := tx.QueryContext(ctx, query, args...)
if err != nil {
return nil, fmt.Errorf("events since cursor (%v, %q) issue %q: %w", cursorCreatedAt, cursorID, issueID, err)
}
defer rows.Close()
return scanEvents(rows)
}
// EventsSinceQuery returns the exact SQL EventsSinceInTx executes for the given
// issueID scope and already-clamped limit, with ? placeholders bound in order by
// the caller: created_at (sargable lower bound), created_at (strict), id
// (same-second tie-break), and issue_id when issueID != "". It is exported so
// the backend sargability guard EXPLAINs this production string rather than a
// hand-copied literal — a change to the SARGABLE predicate here then breaks the
// guard.
//
//nolint:gosec // G201: limit is an int the caller clamps; every runtime value is a bound parameter.
func EventsSinceQuery(issueID string, limit int) string {
query := `
SELECT id, issue_id, event_type, actor, old_value, new_value, comment, created_atView on GitHub (pinned to 71377f2769)
Solutions
- Check database connectivity and retry the operation; if the tx is dead, start a new transaction.
- Verify the events table schema matches the version of the beads storage layer (run schema migration).
- Inspect the wrapped driver error (%w) in the message chain for the root cause.
- Validate cursor arguments (non-empty cursorID when cursorCreatedAt is set) before calling.
Example fix
// before
events, err := EventsSinceInTx(ctx, tx, cursorTime, cursorID, issueID) // err swallowed
// after
if err != nil {
return fmt.Errorf("listing events since %s: %w", cursorTime, err)
} Defensive patterns
Strategy: try-catch
Validate before calling
if cursorCreatedAt != nil && cursorID == "" {
return fmt.Errorf("cursor requires both createdAt and id")
} Try / catch
events, err := EventsSinceInTx(ctx, tx, cur.CreatedAt, cur.ID, issueID)
if err != nil {
var driverErr *driverError // inspect wrapped error via errors.As / errors.Is
if errors.As(err, &driverErr) && isRetryable(driverErr) {
return retryWithNewTx(ctx)
}
return fmt.Errorf("events since %v/%q: %w", cur.CreatedAt, cur.ID, err)
} Prevention
- Retry with a fresh transaction on connection errors; never reuse an aborted tx.
- Keep schema migrations for the events table in lockstep with library upgrades.
- Always pass a paired cursor (createdAt + id) to make pagination stable.
When it happens
Trigger: Calling EventsSinceInTx (directly or via GetEventsInTx / GetAllEventsSinceInTx pagination) when the underlying SQL query fails: malformed query construction, connection loss mid-transaction, or a schema mismatch on the events table.
Common situations: Database connection dropped while paginating a large event log; running against a database whose events table schema is from an older version; transaction already aborted by a prior statement error.
Understand the failure class
Background: "query failed", "%w: SQL error" — wrapped database query errors in Go libraries explained — this error's family across 3 libraries.
Related errors
- delete: drop events: %w
- delete: drop wisp events: %w
- ErrExec
- database not available: %w
- no database connection
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/ebbadb1fa9cfb636.
Report an issue: GitHub.