gastownhall/beads · error

db: LabelSQLRepository.List %s: %w

Error message

db: LabelSQLRepository.List %s: %w

What it means

Wraps failure of the SELECT label query in LabelSQLRepository.List, adding the issue ID. Thrown when the driver rejects the query (connection loss, missing table, permissions), preventing retrieval of an issue's labels.

Source

Thrown at internal/storage/domain/db/label.go:135

		OldValue: label,
	}, domain.RecordEventOpts{UseWispsTable: opts.UseWispsTable}); err != nil {
		return err
	}
	return issueops.RecordEventInTx(ctx, r.runner, issueops.EventUpdate, issueID, actor)
}

func (r *labelSQLRepositoryImpl) List(ctx context.Context, issueID string, opts domain.LabelOpts) ([]string, error) {
	if issueID == "" {
		return nil, fmt.Errorf("db: LabelSQLRepository.List: issueID must not be empty")
	}
	table := pickLabelTable(opts.UseWispsTable)
	//nolint:gosec // G201: table is one of two hardcoded constants
	rows, err := r.runner.QueryContext(ctx,
		fmt.Sprintf("SELECT label FROM %s WHERE issue_id = ? ORDER BY label", table),
		issueID,
	)
	if err != nil {
		return nil, fmt.Errorf("db: LabelSQLRepository.List %s: %w", issueID, err)
	}
	defer rows.Close()

	var out []string
	for rows.Next() {
		var label string
		if err := rows.Scan(&label); err != nil {
			return nil, fmt.Errorf("db: LabelSQLRepository.List: scan: %w", err)
		}
		out = append(out, label)
	}
	if err := rows.Err(); err != nil {
		return nil, fmt.Errorf("db: LabelSQLRepository.List: rows: %w", err)
	}
	return out, nil
}

func (r *labelSQLRepositoryImpl) ListByIssueIDs(ctx context.Context, issueIDs []string, opts domain.LabelOpts) (map[string][]string, error) {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped driver error, especially context.DeadlineExceeded
  2. Verify the labels table exists in this database
  3. Check DB connectivity and pool configuration
  4. Confirm UseWispsTable matches your storage mode

Example fix

// before
ctx := context.Background()
labels, err := repo.List(ctx, issueID, opts)
// after
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
labels, err := repo.List(ctx, issueID, opts)
if err != nil {
    if errors.Is(err, context.DeadlineExceeded) { /* retry */ }
    return err
}
Defensive patterns

Strategy: try-catch

Validate before calling

if issueID == "" { return fmt.Errorf("issueID required") }
ctx, cancel := context.WithTimeout(ctx, 5*time.Second); defer cancel()

Type guard

func isTimeout(err error) bool { return errors.Is(err, context.DeadlineExceeded) }

Try / catch

labels, err := repo.List(ctx, issueID, opts)
if err != nil {
    var sqle *mysql.MySQLError
    switch {
    case errors.Is(err, context.DeadlineExceeded):
        return retry(ctx, issueID, opts)
    case errors.As(err, &sqle) && sqle.Number == 1146:
        return nil, fmt.Errorf("labels table missing; run migrations")
    }
    return nil, err
}

Prevention

When it happens

Trigger: List called when the DB is unreachable, the labels table does not exist, or the query is cancelled via ctx (deadline/context cancellation).

Common situations: Context timeout cancelling a slow query; database not migrated so the labels table is absent; connection pool exhausted; wrong UseWispsTable mode for the current database.

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


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