gastownhall/beads · error

iterate wisp issues by label: %w

Error message

iterate wisp issues by label: %w

What it means

GetIssuesByLabelInTx wraps a row-iteration error from the wisp-issues label query with this message after rows.Scan succeeded but wispRows.Err() reported a driver/SQL failure mid-iteration. It means the ID list is incomplete because the underlying query failed while advancing the result set.

Source

Thrown at internal/storage/issueops/bulk_ops.go:86

	if err := rows.Err(); err != nil {
		return nil, fmt.Errorf("iterate issues by label: %w", err)
	}

	wispRows, err := tx.QueryContext(ctx, `SELECT issue_id FROM wisp_labels WHERE label = ?`, label)
	if err != nil {
		return nil, fmt.Errorf("get wisp issues by label: %w", err)
	}
	defer wispRows.Close()

	for wispRows.Next() {
		var id string
		if err := wispRows.Scan(&id); err != nil {
			return nil, fmt.Errorf("scan wisp issue id: %w", err)
		}
		ids = append(ids, id)
	}
	if err := wispRows.Err(); err != nil {
		return nil, fmt.Errorf("iterate wisp issues by label: %w", err)
	}

	return ids, nil
}

// DeleteConfigInTx removes a configuration value.
func DeleteConfigInTx(ctx context.Context, tx *sql.Tx, key string) error {
	_, err := tx.ExecContext(ctx, "DELETE FROM config WHERE `key` = ?", key)
	if err != nil {
		return fmt.Errorf("delete config %s: %w", key, err)
	}
	return nil
}

// GetCommentsForIssuesInTx retrieves comments for multiple issues, partitioning
// between comments and wisp_comments tables.
//
//nolint:gosec // G201: table is hardcoded

View on GitHub (pinned to 71377f2769)

Solutions

  1. Retry GetIssuesByLabelInTx (the read is idempotent) once the connection/context is healthy.
  2. Inspect the wrapped driver error for connection/cancellation causes; extend the context deadline if it timed out.
  3. Check database server health/logs and connectivity before rerunning.

Example fix

// before
ids, err := issueops.GetIssuesByLabelInTx(ctx, tx, label) // err: iterate wisp issues by label: context deadline exceeded
// after
ctx, cancel := context.WithTimeout(ctx, 60*time.Second)
defer cancel()
ids, err := issueops.GetIssuesByLabelInTx(ctx, tx, label)
if err != nil {
    return retryRead(ctx, label) // bounded retry
}
Defensive patterns

Strategy: retry

Type guard

func isIterationFailure(err error) bool { return err != nil && strings.Contains(err.Error(), "iterate wisp issues by label") }

Try / catch

ids, err := issueops.GetIssuesByLabelInTx(ctx, tx, label)
if err != nil {
    if ctx.Err() != nil || isTransientDB(err) {
        return retryWithBackoff(3, func() error { _, e := issueops.GetIssuesByLabelInTx(ctx, tx, label); return e })
    }
    return err
}

Prevention

When it happens

Trigger: The rows cursor over wisp issues by label hits a database error between Scan calls — connection drop, context cancellation/timeouts, Dolt server restart, or driver-level failure during iteration.

Common situations: Long-running bulk operations on flaky connections; CLI context timeout expiring mid-query; embedded Dolt process killed during a large label scan; network interruption in remote/server mode.

Related errors


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