gastownhall/beads · error
failed to seed issue counter for prefix %q at %d: %w
Error message
failed to seed issue counter for prefix %q at %d: %w
What it means
SeedCounterFromExistingIssuesTx computed maxNum from existing issue IDs and failed to INSERT the seed row (prefix, maxNum) into issue_counter. The wrapped SQL error is the cause — typically a missing table, a duplicate-prefix constraint race, or a transaction error.
Source
Thrown at internal/storage/issueops/helpers.go:310
if err := rows.Scan(&id); err != nil {
continue
}
suffix := strings.TrimPrefix(id, pfxDash)
if strings.Contains(suffix, ".") {
continue // skip child IDs
}
if n, err := strconv.Atoi(suffix); err == nil && n > maxNum {
maxNum = n
}
}
if err := rows.Err(); err != nil {
return fmt.Errorf("failed to iterate issues for prefix %q: %w", prefix, err)
}
if maxNum > 0 {
_, err = tx.ExecContext(ctx, "INSERT INTO issue_counter (prefix, last_id) VALUES (?, ?)", prefix, maxNum)
if err != nil {
return fmt.Errorf("failed to seed issue counter for prefix %q at %d: %w", prefix, maxNum, err)
}
}
return nil
}
// GetAdaptiveIDLengthTx returns the appropriate hash length based on database size.
//
//nolint:gosec // G201: table is a hardcoded constant
func GetAdaptiveIDLengthTx(ctx context.Context, tx DBTX, table, prefix string) (int, error) {
var count int
err := tx.QueryRowContext(ctx, fmt.Sprintf(`
SELECT COUNT(*)
FROM %s
WHERE id LIKE CONCAT(?, '-%%')
AND INSTR(SUBSTRING(id, LENGTH(?) + 2), '.') = 0
`, table), prefix, prefix).Scan(&count)
if err != nil {
return 6, errView on GitHub (pinned to 71377f2769)
Solutions
- Run schema migrations so issue_counter exists.
- Use INSERT ... ON DUPLICATE KEY UPDATE / INSERT OR IGNORE semantics (or retry) to tolerate concurrent seeding races.
- Serialize writer access: avoid multiple concurrent bd processes on one DB, or take bd's write lock.
- Check the wrapped error for constraint vs. table-missing vs. permission causes and address specifically.
Example fix
// before (naive insert, races with concurrent seed) _, err = tx.ExecContext(ctx, "INSERT INTO issue_counter (prefix, last_id) VALUES (?, ?)", prefix, maxNum) // after (idempotent seeding at call site) _, err = tx.ExecContext(ctx, `INSERT INTO issue_counter (prefix, last_id) VALUES (?, ?) ON DUPLICATE KEY UPDATE last_id = GREATEST(last_id, VALUES(last_id))`, prefix, maxNum)
Defensive patterns
Strategy: retry
Validate before calling
var n int
if err := tx.QueryRowContext(ctx, "SELECT COUNT(*) FROM issue_counter").Scan(&n); err != nil {
return fmt.Errorf("run migrations first: %w", err)
} Try / catch
if err != nil && strings.Contains(err.Error(), "failed to seed issue counter") {
// likely a concurrent-seed PK conflict; retry — seeding is idempotent
time.Sleep(50 * time.Millisecond)
return seedAndGenerate(ctx)
} Prevention
- Serialize writers (bd write lock) to avoid two processes seeding the same prefix.
- Prefer idempotent upsert semantics for seed rows.
- Migrate the schema before enabling counter mode.
When it happens
Trigger: First-time counter seeding for a prefix with existing issues: INSERT INTO issue_counter (prefix, last_id) VALUES (?, ?) fails — issue_counter table absent (unmigrated DB), a concurrent transaction inserted the same prefix row (primary-key conflict), or the tx was aborted.
Common situations: Two bd processes seeding the same prefix simultaneously; counter mode enabled on a DB that predates the issue_counter table; permission-restricted database user.
Related errors
- failed to insert initial issue counter for prefix %q: %w
- failed to insert initial issue counter for prefix %q: %w
- failed to read issue counter after increment for prefix %q:
- failed to check existing counter for prefix %q: %w
- schema: verify fresh-bootstrap history: got %d commits, want
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/350b74603e9ec2c3.
Report an issue: GitHub.