{"record":{"id":"f39ffcced59aa436","repo":"gastownhall/beads","slug":"failed-to-read-issue-id-mode-config-w-f39ffc","errorCode":null,"errorMessage":"failed to read issue_id_mode config: %w","messagePattern":"failed to read issue_id_mode config: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/helpers.go","lineNumber":224,"sourceCode":"\t\t\tif err != nil {\n\t\t\t\treturn \"\", fmt.Errorf(\"failed to check for ID collision: %w\", err)\n\t\t\t}\n\n\t\t\tif count == 0 {\n\t\t\t\treturn candidate, nil\n\t\t\t}\n\t\t}\n\t}\n\n\treturn \"\", fmt.Errorf(\"failed to generate unique ID after trying lengths %d-%d with 10 nonces each\", baseLength, maxLength)\n}\n\n// IsCounterModeTx checks whether issue_id_mode=counter is configured.\nfunc IsCounterModeTx(ctx context.Context, tx DBTX) (bool, error) {\n\tvar idMode string\n\terr := tx.QueryRowContext(ctx, \"SELECT value FROM config WHERE `key` = ?\", \"issue_id_mode\").Scan(&idMode)\n\tif err != nil && err != sql.ErrNoRows {\n\t\treturn false, fmt.Errorf(\"failed to read issue_id_mode config: %w\", err)\n\t}\n\treturn idMode == \"counter\", nil\n}\n\n// NextCounterIDTx atomically increments and returns the next sequential issue ID.\nfunc NextCounterIDTx(ctx context.Context, tx DBTX, prefix string) (string, error) {\n\tres, err := tx.ExecContext(ctx, \"UPDATE issue_counter SET last_id = last_id + 1 WHERE prefix = ?\", prefix)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to increment issue counter for prefix %q: %w\", prefix, err)\n\t}\n\n\trowsAffected, err := res.RowsAffected()\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to check rows affected for issue counter prefix %q: %w\", prefix, err)\n\t}\n\n\tif rowsAffected == 0 {\n\t\tif seedErr := SeedCounterFromExistingIssuesTx(ctx, tx, prefix); seedErr != nil {","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/helpers.go#L206-L242","documentation":"IsCounterModeTx reads the issue_id_mode row from the config table to decide whether issue IDs are generated by counter or by hash probing. This error means that SELECT failed with something other than 'no rows' — i.e., a genuine query failure, not an unset config. A missing config row is explicitly tolerated and treated as non-counter (hash) mode.","triggerScenarios":"Calling GenerateIssueIDInTable (which calls IsCounterModeTx) when the config table is missing/corrupted, the query hits a lock timeout, the transaction is dead, or the connection fails mid-query. Note: sql.ErrNoRows is deliberately NOT an error path here.","commonSituations":"Fresh database where the config table was never created (pre-migration state); database locked by a concurrent writer; corrupted config table after a crashed migration.","solutions":["Inspect the wrapped driver error to identify the root cause (missing table vs lock vs connection)","Create/verify the config table exists with the expected key column: SELECT value FROM config WHERE key = 'issue_id_mode'","Set the mode explicitly if desired: insert issue_id_mode = 'counter' (or 'hash') into config","Run schema migrations/bd doctor to repair a missing or corrupted config table"],"exampleFix":"// before\nerr = tx.QueryRowContext(ctx, \"SELECT value FROM config WHERE `key` = ?\", \"issue_id_mode\").Scan(&idMode)\nif err != nil && err != sql.ErrNoRows {\n\treturn false, fmt.Errorf(\"failed to read issue_id_mode config: %w\", err)\n}\n// after\nerr = tx.QueryRowContext(ctx, \"SELECT value FROM config WHERE `key` = ?\", \"issue_id_mode\").Scan(&idMode)\nif errors.Is(err, sql.ErrNoRows) {\n\treturn false, nil // unset config: default hash mode\n}\nif err != nil {\n\treturn false, fmt.Errorf(\"failed to read issue_id_mode config: %w\", err)\n}","handlingStrategy":"try-catch","validationCode":"// verify config table exists before generation\nvar n int\nif err := tx.QueryRowContext(ctx, `SELECT COUNT(*) FROM sqlite_master WHERE name = 'config'`).Scan(&n); err == nil && n == 0 {\n\treturn errors.New(\"config table missing: run bd init/migrations\")\n}","typeGuard":null,"tryCatchPattern":"isCounter, err := IsCounterModeTx(ctx, tx)\nif err != nil {\n\tif strings.Contains(err.Error(), \"no such table\") {\n\t\t// treat as hash mode default or run migrations first\n\t\tisCounter = false\n\t} else {\n\t\treturn fmt.Errorf(\"id mode lookup: %w\", err)\n\t}\n}","preventionTips":["Initialize the config table during database setup, before any issue creation","Set issue_id_mode explicitly instead of relying on the no-rows default","Run migrations/bd doctor after version upgrades","Avoid concurrent writers contending for the config table during ID generation"],"tags":["database","config","sql","id-generation"],"backgroundTag":"config-read-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}