gastownhall/beads · error
failed to insert initial issue counter for prefix %q: %w
Error message
failed to insert initial issue counter for prefix %q: %w
What it means
NextCounterIDTx failed to insert the first row (last_id=1) into the issue_counter table for a prefix. This fallback runs only after the UPDATE increment matched 0 rows and seeding from existing issues also left no row (e.g. no existing issues with that prefix). The wrapped SQL error is the real cause (table missing, constraint violation, permissions, DB connection).
Source
Thrown at internal/storage/issueops/helpers.go:256
return "", fmt.Errorf("failed to check rows affected for issue counter prefix %q: %w", prefix, err)
}
if rowsAffected == 0 {
if seedErr := SeedCounterFromExistingIssuesTx(ctx, tx, prefix); seedErr != nil {
return "", fmt.Errorf("failed to seed issue counter for prefix %q: %w", prefix, seedErr)
}
res, err = tx.ExecContext(ctx, "UPDATE issue_counter SET last_id = last_id + 1 WHERE prefix = ?", prefix)
if err != nil {
return "", fmt.Errorf("failed to increment issue counter after seeding for prefix %q: %w", prefix, err)
}
rowsAffected, err = res.RowsAffected()
if err != nil {
return "", fmt.Errorf("failed to check rows affected after seeding for prefix %q: %w", prefix, err)
}
if rowsAffected == 0 {
_, err = tx.ExecContext(ctx, "INSERT INTO issue_counter (prefix, last_id) VALUES (?, 1)", prefix)
if err != nil {
return "", fmt.Errorf("failed to insert initial issue counter for prefix %q: %w", prefix, err)
}
}
}
var nextID int
err = tx.QueryRowContext(ctx, "SELECT last_id FROM issue_counter WHERE prefix = ?", prefix).Scan(&nextID)
if err != nil {
return "", fmt.Errorf("failed to read issue counter after increment for prefix %q: %w", prefix, err)
}
return fmt.Sprintf("%s-%d", prefix, nextID), nil
}
// 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.
func SeedCounterFromExistingIssuesTx(ctx context.Context, tx DBTX, prefix string) error {
var existing int
err := tx.QueryRowContext(ctx, "SELECT last_id FROM issue_counter WHERE prefix = ?", prefix).Scan(&existing)
if err == nil {View on GitHub (pinned to 71377f2769)
Solutions
- Run schema migrations so the issue_counter table exists (bd should apply migrations on open; verify with a SELECT 1 FROM issue_counter query).
- Pre-seed the counter manually: INSERT INTO issue_counter (prefix, last_id) VALUES ('<PREFIX>', 0), then retry ID generation.
- Read the wrapped %w error: if it is 'no such table', apply migrations; if it is a connection/lock error, retry the operation.
- Check DB connectivity and that the transaction is still valid (not rolled back/timed out) before calling again.
Example fix
// before: counter mode on an unmigrated DB fails with 'no such table: issue_counter'
// after
// apply migrations at startup before generating IDs
db.SetDefaultMigrationTimeout(30 * time.Second)
if err := storage.Migrate(ctx, db); err != nil { log.Fatal(err) }
id, err := storage.GenerateIssueIDInTable(ctx, tx, "issues", "PROJ", issue) Defensive patterns
Strategy: retry
Validate before calling
var exists int
if err := tx.QueryRowContext(ctx, "SELECT COUNT(*) FROM issue_counter").Scan(&exists); err != nil {
return fmt.Errorf("issue_counter table missing; run migrations first: %w", err)
} Try / catch
id, err := storage.GenerateIssueIDInTable(ctx, tx, "issues", prefix, issue)
if err != nil {
var inner error
if errors.As(err, &inner) && strings.Contains(inner.Error(), "no such table") {
if mErr := storage.Migrate(ctx, db); mErr != nil { log.Fatal(mErr) }
id, err = storage.GenerateIssueIDInTable(ctx, tx, "issues", prefix, issue)
}
} Prevention
- Always run schema migrations at startup before any bd storage operation.
- After enabling issue_id_mode=counter, smoke-test ID generation in CI.
- Pre-seed counters for custom prefixes when provisioning a new project.
When it happens
Trigger: Calling GenerateIssueIDInTable (counter mode) with a prefix that has no issue_counter row and no existing issues: the INSERT INTO issue_counter (prefix, last_id) VALUES (?, 1) fails, typically because the issue_counter table does not exist (old schema, not migrated) or the tx/DB is broken.
Common situations: Dolt database created before the counter-mode schema migration; counter mode enabled via issue_id_mode=counter but migrations not applied; a custom prefix used for the first issue ever; read-only or crashed connection mid-transaction.
Related errors
- failed to check existing counter for prefix %q: %w
- schema: read database name: %w
- schema migration: %w
- failed to read issue counter after increment for prefix %q:
- failed to seed issue counter for prefix %q at %d: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/b464edbf2ab22e78.
Report an issue: GitHub.