gastownhall/beads · error

failed to query existing issues for prefix

Error message

failed to query existing issues for prefix %q: %w

What it means

When no issue_counter row exists for a prefix, the seeder scans existing issues with a LIKE query to find the highest numeric suffix; failure of that scan query is wrapped with this message. The counter cannot be safely seeded without this scan, so the operation aborts.

Solutions

  1. Read the wrapped cause and fix the underlying SQL/connection error
  2. Retry the operation; seeding is read-only up to the failure point
  3. Verify the issues table exists and is queryable (bd list)
  4. Ensure schema migrations ran so both issues and issue_counter are present
Defensive patterns

Strategy: retry

Validate before calling

// Ensure the issues table exists and is readable before creating issues
const count = await query("SELECT COUNT(*) FROM issues");

Try / catch

try {
  await bd.create(title);
} catch (e) {
  if (String(e.message).includes("failed to query existing issues")) {
    // check connectivity/migrations, then retry
  } else throw e;
}

Prevention

When it happens

Trigger: First ID generation for a prefix with no counter row, where SELECT id FROM issues WHERE id LIKE 'prefix-%' fails — SQL error, transaction failure, or backend unavailable.

Common situations: Databases created before the counter table existed (legacy data being adopted); transient connection loss during first create after migration; very large issue tables timing out.

Related errors


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

Appendix: source

Thrown at internal/storage/dolt/issues.go:808

// It is idempotent: if a counter row already exists for this prefix, it does nothing.
func seedCounterFromExistingIssuesTx(ctx context.Context, tx *sql.Tx, prefix string) error {
	// Check whether a counter row already exists for this prefix.
	// If it does, we must not overwrite it (the counter may already be in use).
	var existing int
	err := tx.QueryRowContext(ctx, "SELECT last_id FROM issue_counter WHERE prefix = ?", prefix).Scan(&existing)
	if err == nil {
		// Row exists - counter is already initialized, nothing to do.
		return nil
	}
	if err != sql.ErrNoRows {
		return fmt.Errorf("failed to check issue_counter for prefix %q: %w", prefix, err)
	}

	// No counter row yet. Scan existing issues to find the highest numeric suffix.
	likePattern := prefix + "-%"
	rows, err := tx.QueryContext(ctx, "SELECT id FROM issues WHERE id LIKE ?", likePattern)
	if err != nil {
		return fmt.Errorf("failed to query existing issues for prefix %q: %w", prefix, err)
	}
	defer rows.Close()

	maxNum := 0
	prefixDash := prefix + "-"
	for rows.Next() {
		var id string
		if err := rows.Scan(&id); err != nil {
			return fmt.Errorf("failed to scan issue id: %w", err)
		}
		// Strip the prefix and attempt to parse the remainder as an integer.
		suffix := strings.TrimPrefix(id, prefixDash)
		if suffix == id {
			// id did not start with prefix- (should not happen given LIKE, but be safe)
			continue
		}
		var num int
		if _, parseErr := fmt.Sscanf(suffix, "%d", &num); parseErr == nil && fmt.Sprintf("%d", num) == suffix {

View on GitHub (pinned to 71377f2769)