{"record":{"id":"65fca9ab5dd8fd3d","repo":"gastownhall/beads","slug":"failed-to-check-existing-counter-for-prefix-q-w","errorCode":null,"errorMessage":"failed to check existing counter for prefix %q: %w","messagePattern":"failed to check existing counter for prefix %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/helpers.go","lineNumber":278,"sourceCode":"\n\tvar nextID int\n\terr = tx.QueryRowContext(ctx, \"SELECT last_id FROM issue_counter WHERE prefix = ?\", prefix).Scan(&nextID)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to read issue counter after increment for prefix %q: %w\", prefix, err)\n\t}\n\treturn fmt.Sprintf(\"%s-%d\", prefix, nextID), nil\n}\n\n// SeedCounterFromExistingIssuesTx scans existing issues to find the highest numeric suffix\n// for the given prefix, then seeds the issue_counter table if no row exists yet.\nfunc SeedCounterFromExistingIssuesTx(ctx context.Context, tx DBTX, prefix string) error {\n\tvar existing int\n\terr := tx.QueryRowContext(ctx, \"SELECT last_id FROM issue_counter WHERE prefix = ?\", prefix).Scan(&existing)\n\tif err == nil {\n\t\treturn nil // already seeded\n\t}\n\tif err != sql.ErrNoRows {\n\t\treturn fmt.Errorf(\"failed to check existing counter for prefix %q: %w\", prefix, err)\n\t}\n\n\t// Find max numeric suffix among existing issues\n\trows, err := tx.QueryContext(ctx, `SELECT id FROM issues WHERE id LIKE CONCAT(?, '-%')`, prefix)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to scan existing issues for prefix %q: %w\", prefix, err)\n\t}\n\tdefer rows.Close()\n\n\tmaxNum := 0\n\tpfxDash := prefix + \"-\"\n\tfor rows.Next() {\n\t\tvar id string\n\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, \".\") {","sourceCodeStart":260,"sourceCodeEnd":296,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/helpers.go#L260-L296","documentation":"SeedCounterFromExistingIssuesTx probes the issue_counter table to see if the prefix is already seeded; the probe failed with an error other than 'no rows'. This is a database-level failure (table missing, connection error, query error), not a 'not seeded yet' condition.","triggerScenarios":"Called from NextCounterIDTx when an UPDATE on issue_counter matched 0 rows: the initial SELECT last_id ... Scan returns a non-ErrNoRows error — most commonly 'no such table: issue_counter' on an unmigrated Dolt database.","commonSituations":"Database created before counter-mode migration; corrupted or partially restored .beads Dolt database; connecting to a DB with insufficient privileges to read issue_counter.","solutions":["Apply schema migrations so issue_counter exists, then retry (the seeding will then succeed or find the row).","Inspect the wrapped error: 'no such table' → migrate; permission denied → grant SELECT on issue_counter.","Verify DB file integrity / re-clone via 'bd bootstrap' if the .beads database is corrupted.","Check driver connection health before the operation if errors are transient."],"exampleFix":"// before: old DB without issue_counter table\n// after\nif err := storage.Migrate(ctx, db); err != nil { return err }\nid, err := storage.GenerateIssueIDInTable(ctx, tx, \"issues\", prefix, issue)","handlingStrategy":"validation","validationCode":"if _, err := tx.QueryContext(ctx, \"SELECT 1 FROM issue_counter LIMIT 1\"); err != nil {\n    return fmt.Errorf(\"run migrations: issue_counter table unavailable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"id, err := storage.GenerateIssueIDInTable(ctx, tx, \"issues\", prefix, issue)\nif err != nil && strings.Contains(err.Error(), \"failed to check existing counter\") {\n    if mErr := storage.Migrate(ctx, db); mErr != nil { return mErr }\n    id, err = storage.GenerateIssueIDInTable(ctx, tx, \"issues\", prefix, issue)\n}","preventionTips":["Gate counter mode on a migration check at startup.","Treat any non-ErrNoRows error from the counter probe as a hard infra failure, not a seeding gap.","Keep driver and schema versions in sync (bd upgrade + migrate together)."],"tags":["database","schema-migration","counter","go"],"backgroundTag":"missing-table-issue-counter","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}