gastownhall/beads · error

stale issues rows: %w

Error message

stale issues rows: %w

What it means

After iterating rows, GetStaleIssuesInTx calls rows.Err() to detect failures that occurred during row iteration and wraps it with 'stale issues rows: %w'. This means the connection dropped or the query was aborted partway through streaming the stale issue ids — not a query-preparation or scan problem.

Source

Thrown at internal/storage/issueops/stale.go:83

	if err != nil {
		return nil, fmt.Errorf("failed to get stale issues: %w", err)
	}

	// Collect IDs first, then batch-fetch full issues.
	// Close rows explicitly before the nested fetch — MySQL/Dolt drivers
	// can't handle multiple active result sets on one connection.
	var ids []string
	for rows.Next() {
		var id string
		if err := rows.Scan(&id); err != nil {
			rows.Close()
			return nil, fmt.Errorf("failed to scan stale issue id: %w", err)
		}
		ids = append(ids, id)
	}
	if err := rows.Err(); err != nil {
		rows.Close()
		return nil, fmt.Errorf("stale issues rows: %w", err)
	}
	rows.Close()

	if len(ids) == 0 {
		return nil, nil
	}

	// GetIssuesByIDsInTx returns issues in arbitrary order (WHERE IN),
	// so re-order to preserve the updated_at ASC ordering from the query.
	issues, err := GetIssuesByIDsInTx(ctx, tx, ids, nil)
	if err != nil {
		return nil, err
	}

	issueByID := make(map[string]*types.Issue, len(issues))
	for _, iss := range issues {
		if iss != nil {
			issueByID[iss.ID] = iss

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the wrapped driver error to distinguish connection-lost vs context cancelled.
  2. Retry the whole operation with a fresh transaction and connection — iteration errors are typically transient.
  3. Increase client/server idle and read timeouts if scans of large tables routinely exceed them.
  4. Keep the ctx deadline generous enough for the row count expected, and avoid sharing the tx across goroutines.

Example fix

// before
issues, err := GetStaleIssuesInTx(ctx, tx, filter) // dies mid-iteration on slow network
// after
for attempt := 0; attempt < 3; attempt++ {
    issues, err = GetStaleIssuesInTx(ctx, tx, filter)
    if err == nil { break }
    time.Sleep(time.Second * time.Duration(attempt+1))
}
Defensive patterns

Strategy: retry

Validate before calling

// ensure the connection is healthy before a long streaming scan
if err := tx.PingContext(ctx); err != nil { return fmt.Errorf("connection unhealthy: %w", err) }

Try / catch

issues, err := issueops.GetStaleIssuesInTx(ctx, tx, filter)
if err != nil && strings.Contains(err.Error(), "stale issues rows:") {
    // transient iteration failure: reopen tx and retry with backoff
}

Prevention

When it happens

Trigger: Network interruption to the Dolt/MySQL server while rows are being streamed; server-side query kill or timeout during iteration; context cancellation while rows.Next() is advancing; connection closed by the pool mid-iteration.

Common situations: Long stale scans over big issues tables hitting an idle-connection timeout; flaky network to a remote Dolt server; server restarts during a sweep/stale job; proxy/load-balancer idle timeouts.

Related errors


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