gastownhall/beads · error
failed to check issue_counter for prefix %q: %w
Error message
failed to check issue_counter for prefix %q: %w
What it means
seedCounterFromExistingIssuesTx initializes the issue_counter table by reading last_id for a prefix; if the SELECT fails with an error other than sql.ErrNoRows, it is wrapped here. This is a query failure, not a missing row (missing row is expected and handled by seeding).
Source
Thrown at internal/storage/dolt/issues.go:801
return wrapExecError("record event", issueops.RecordFullEventInTable(ctx, tx, "events", issueID, eventType, actor, oldValue, newValue))
}
// seedCounterFromExistingIssuesTx scans existing issues to find the highest numeric suffix
// for the given prefix, then seeds the issue_counter table if no row exists yet.
// This is called when counter mode is first enabled on a repo that already has issues,
// to prevent counter collisions with manually-created sequential IDs (GH#2002).
// 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.View on GitHub (pinned to 71377f2769)
Solutions
- Read the wrapped cause; check server connectivity and retry
- Verify the issue_counter table exists with columns (prefix, last_id); re-run schema migrations if not
- Run bd doctor to check database integrity
- If corruption is suspected, restore from backup or re-initialize the database
Defensive patterns
Strategy: retry
Validate before calling
// Verify database schema before ID generation
const ok = await tableExists("issue_counter"); // prefix TEXT, last_id BIGINT
if (!ok) throw new Error("run migrations: issue_counter missing"); Try / catch
try {
await bd.create(title);
} catch (e) {
if (String(e.message).includes("failed to check issue_counter")) {
await runMigrations(); // then retry
} else throw e;
} Prevention
- Keep schema migrations current so issue_counter always exists
- Run bd doctor after database moves or restores
- Retry transient connection errors with backoff
- Monitor Dolt server health in automated pipelines
When it happens
Trigger: Generating the next counter-based ID (nextCounterIDTx) when the issue_counter SELECT fails — connection errors, table missing/corrupt, transaction aborted.
Common situations: Fresh or migrated databases where issue_counter schema is missing; transient Dolt server failures mid-transaction; corrupted database files.
Related errors
- failed to query existing issues for prefix %q: %w
- failed to seed issue_counter for prefix %q at %d: %w
- comment counts: %w
- ErrQuery
- ErrExec
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/1643755115f0df64.
Report an issue: GitHub.