{"record":{"id":"350b74603e9ec2c3","repo":"gastownhall/beads","slug":"failed-to-seed-issue-counter-for-prefix-q-at-d-350b74","errorCode":null,"errorMessage":"failed to seed issue counter for prefix %q at %d: %w","messagePattern":"failed to seed issue counter for prefix %q at (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/helpers.go","lineNumber":310,"sourceCode":"\t\tif err := rows.Scan(&id); err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tsuffix := strings.TrimPrefix(id, pfxDash)\n\t\tif strings.Contains(suffix, \".\") {\n\t\t\tcontinue // skip child IDs\n\t\t}\n\t\tif n, err := strconv.Atoi(suffix); err == nil && n > maxNum {\n\t\t\tmaxNum = n\n\t\t}\n\t}\n\tif err := rows.Err(); err != nil {\n\t\treturn fmt.Errorf(\"failed to iterate issues for prefix %q: %w\", prefix, err)\n\t}\n\n\tif maxNum > 0 {\n\t\t_, err = tx.ExecContext(ctx, \"INSERT INTO issue_counter (prefix, last_id) VALUES (?, ?)\", prefix, maxNum)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to seed issue counter for prefix %q at %d: %w\", prefix, maxNum, err)\n\t\t}\n\t}\n\treturn nil\n}\n\n// GetAdaptiveIDLengthTx returns the appropriate hash length based on database size.\n//\n//nolint:gosec // G201: table is a hardcoded constant\nfunc GetAdaptiveIDLengthTx(ctx context.Context, tx DBTX, table, prefix string) (int, error) {\n\tvar count int\n\terr := tx.QueryRowContext(ctx, fmt.Sprintf(`\n\t\tSELECT COUNT(*)\n\t\tFROM %s\n\t\tWHERE id LIKE CONCAT(?, '-%%')\n\t\t  AND INSTR(SUBSTRING(id, LENGTH(?) + 2), '.') = 0\n\t`, table), prefix, prefix).Scan(&count)\n\tif err != nil {\n\t\treturn 6, err","sourceCodeStart":292,"sourceCodeEnd":328,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/helpers.go#L292-L328","documentation":"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.","triggerScenarios":"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.","commonSituations":"Two bd processes seeding the same prefix simultaneously; counter mode enabled on a DB that predates the issue_counter table; permission-restricted database user.","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."],"exampleFix":"// before (naive insert, races with concurrent seed)\n_, err = tx.ExecContext(ctx, \"INSERT INTO issue_counter (prefix, last_id) VALUES (?, ?)\", prefix, maxNum)\n// after (idempotent seeding at call site)\n_, err = tx.ExecContext(ctx, `INSERT INTO issue_counter (prefix, last_id) VALUES (?, ?)\n  ON DUPLICATE KEY UPDATE last_id = GREATEST(last_id, VALUES(last_id))`, prefix, maxNum)","handlingStrategy":"retry","validationCode":"var n int\nif err := tx.QueryRowContext(ctx, \"SELECT COUNT(*) FROM issue_counter\").Scan(&n); err != nil {\n    return fmt.Errorf(\"run migrations first: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"failed to seed issue counter\") {\n    // likely a concurrent-seed PK conflict; retry — seeding is idempotent\n    time.Sleep(50 * time.Millisecond)\n    return seedAndGenerate(ctx)\n}","preventionTips":["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."],"tags":["database","counter","race-condition","go"],"backgroundTag":"counter-seed-insert-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}