gastownhall/beads · error

db: RawSQL Query: rows: %w

Error message

db: RawSQL Query: rows: %w

What it means

Wraps the value of rows.Err() after finishing iteration in RawSQLRepository.Query. rows.Err() reports an error that terminated the rows.Next() loop early, meaning the result set was only partially read. It exists because database/sql surfaces driver/network failures during iteration through Err(), not through Scan.

Source

Thrown at internal/storage/domain/db/raw_sql.go:50

	result := &domain.RawSQLResult{Columns: columns}
	for rows.Next() {
		values := make([]any, len(columns))
		ptrs := make([]any, len(columns))
		for i := range values {
			ptrs[i] = &values[i]
		}
		if err := rows.Scan(ptrs...); err != nil {
			return nil, fmt.Errorf("db: RawSQL Query: scan: %w", err)
		}
		for i, v := range values {
			if b, ok := v.([]byte); ok {
				values[i] = string(b)
			}
		}
		result.Rows = append(result.Rows, values)
	}
	if err := rows.Err(); err != nil {
		return nil, fmt.Errorf("db: RawSQL Query: rows: %w", err)
	}
	return result, nil
}

func (r *rawSQLRepositoryImpl) Exec(ctx context.Context, query string, args ...any) (int64, error) {
	res, err := r.runner.ExecContext(ctx, query, args...)
	if err != nil {
		return 0, fmt.Errorf("db: RawSQL Exec: %w", err)
	}
	affected, err := res.RowsAffected()
	if err != nil {
		return 0, fmt.Errorf("db: RawSQL Exec: rows affected: %w", err)
	}
	return affected, nil
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped error for context deadline/cancellation and increase the timeout or narrow the query
  2. Add LIMIT/pagination to keep result sets small so iteration finishes before any timeout
  3. Retry the query on transient network errors
  4. Verify DB connection liveness/idle timeouts between client and server

Example fix

// before
rows, err := repo.Query(ctx, "SELECT id FROM issues")
// after: bound the work so iteration completes
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
rows, err := repo.Query(ctx, "SELECT id FROM issues LIMIT 1000")
Defensive patterns

Strategy: retry

Validate before calling

// prefer bounded result sets
const maxRows = 10000
q := "SELECT id FROM issues LIMIT " + strconv.Itoa(maxRows)

Type guard

func isRowsIterationError(err error) bool {
	return err != nil && strings.Contains(err.Error(), "RawSQL Query: rows")
}

Try / catch

res, err := repo.Query(ctx, q)
if err != nil && isRowsIterationError(err) {
	if errors.Is(err, context.DeadlineExceeded) { /* raise timeout or paginate */ }
	// retry once on transient network errors
}

Prevention

When it happens

Trigger: Calling RawSQLRepository.Query when the underlying connection is lost or the context is canceled while rows are still being streamed from the server.

Common situations: Long-running raw queries over slow/unstable links; server-side timeouts killing the connection mid-stream; context deadline exceeded while fetching a large result set.

Related errors


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