gastownhall/beads · error
scan event: %w
Error message
scan event: %w
What it means
scanEvents iterates result rows from an events query and scans each row into a types.Event. This error wraps rows.Scan failing for a particular row — usually a column count or type mismatch between the SELECT and the scan targets (e.g. NULL handling or changed column order/type). The whole event listing fails rather than returning partial data.
Source
Thrown at internal/storage/issueops/events.go:142
query := `
SELECT id, issue_id, event_type, actor, old_value, new_value, comment, created_at
FROM events
WHERE created_at >= ? AND ((created_at > ?) OR (id > ?))`
if issueID != "" {
query += " AND issue_id = ?"
}
query += fmt.Sprintf(" ORDER BY created_at ASC, id ASC LIMIT %d", limit)
return query
}
func scanEvents(rows *sql.Rows) ([]*types.Event, error) {
var events []*types.Event
for rows.Next() {
var event types.Event
var oldValue, newValue, comment sql.NullString
if err := rows.Scan(&event.ID, &event.IssueID, &event.EventType, &event.Actor,
&oldValue, &newValue, &comment, &event.CreatedAt); err != nil {
return nil, fmt.Errorf("scan event: %w", err)
}
if oldValue.Valid {
event.OldValue = &oldValue.String
}
if newValue.Valid {
event.NewValue = &newValue.String
}
if comment.Valid {
event.Comment = &comment.String
}
events = append(events, &event)
}
return events, rows.Err()
}
View on GitHub (pinned to 71377f2769)
Solutions
- Compare the events table schema against the SELECT column list in the issueops events query and align them.
- Run the library's schema migration to restore the expected events table shape.
- Check for NULL/empty strings in old_value/new_value/comment columns; they are scanned via sql.NullString so true type mismatches are the culprit.
- Inspect the wrapped error for the exact column index that failed.
Example fix
// before var oldValue string rows.Scan(&event.ID, &oldValue) // fails on NULL // after var oldValue sql.NullString rows.Scan(&event.ID, &oldValue)
Defensive patterns
Strategy: try-catch
Validate before calling
// Verify table shape before scanning:
rows, err := tx.QueryContext(ctx, "SELECT id, issue_id, event_type, actor, old_value, new_value, comment, created_at FROM events LIMIT 1")
if err != nil {
return fmt.Errorf("events table schema mismatch: %w", err)
}
rows.Close() Try / catch
events, err := scanEvents(rows)
if err != nil {
return fmt.Errorf("reading event rows failed (schema drift?): %w", err)
} Prevention
- Run schema migration after every library upgrade before issuing queries.
- Avoid manual edits to the events table schema (no added/dropped/reordered columns).
- Keep nullable columns (old_value, new_value, comment) typed as NULL-able strings so sql.NullString scans succeed.
When it happens
Trigger: Any events query returning rows whose shape does not match Scan(&ID, &IssueID, &EventType, &Actor, oldValue, newValue, comment, &CreatedAt): schema drift, a driver that returns unexpected types for nullable columns, or corrupted rows.
Common situations: Database migrated between versions so the events table gained/dropped columns; custom Dolt schema edits; driver type mapping changes after a driver upgrade.
Related errors
- search %s (hydrate): scan: %w
- ErrScan
- failed to scan dependency keys: %w
- %s: %w
- failed to scan federation peer: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/39fabc78082e8ab8.
Report an issue: GitHub.