{"record":{"id":"1c7f1ae310b25d3d","repo":"gastownhall/beads","slug":"journal-read-seq-counter-w","errorCode":null,"errorMessage":"journal: read seq counter: %w","messagePattern":"journal: read seq counter: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/journal.go","lineNumber":539,"sourceCode":"\t\treturn res.RowsAffected()\n\t}\n\tn, err := advance()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tif n == 0 {\n\t\t// The counter row is missing entirely: seed it at the journal's\n\t\t// high-water mark, so the re-seed can never collide with an existing seq.\n\t\tif err := healEventSeqCounter(ctx, tx); err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\tif _, err := advance(); err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t}\n\tvar seq int64\n\tif err := tx.QueryRowContext(ctx, \"SELECT next_seq FROM bd_events_seq WHERE id = 0\").Scan(&seq); err != nil {\n\t\treturn 0, fmt.Errorf(\"journal: read seq counter: %w\", err)\n\t}\n\treturn seq, nil\n}\n\n// compile-time assurance that *sql.Tx satisfies DBTX (the emit helpers accept\n// both *sql.Tx and *sql.DB via DBTX).\nvar _ DBTX = (*sql.Tx)(nil)\n","sourceCodeStart":521,"sourceCodeEnd":547,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/journal.go#L521-L547","documentation":"After advancing (or healing via the duplicate-key reactive path in insertEventRow), nextEventSeq reads the allocated value with SELECT next_seq FROM bd_events_seq WHERE id = 0. This error wraps that read failing. Unlike journal_prune.go's version, ErrNoRows here is NOT tolerated — the seq row must exist because advance() either incremented it or created/healed it.","triggerScenarios":"insertEventRow calling nextEventSeq when the SELECT on bd_events_seq returns a driver error (connection lost, table missing) — or returns ErrNoRows, which happens only if the row with id=0 vanished or the healing insert path silently failed to create it.","commonSituations":"Schema drift: bd_events_seq dropped or the id=0 row deleted manually; migration partially applied; transaction rolled back upstream so the healed row is invisible.","solutions":["Verify the sentinel row exists: SELECT next_seq FROM bd_events_seq WHERE id = 0; re-insert it (INSERT INTO bd_events_seq (id, next_seq) VALUES (0, 1)) if missing.","Re-run the schema migration to recreate bd_events_seq and its seed row.","Retry the operation if the wrapped error is transient (connection/lock).","Check for concurrent maintenance jobs that might truncate or rewrite bd_events_seq."],"exampleFix":"// before\nDELETE FROM bd_events_seq;            -- breaks next allocation\n// after\nUPDATE bd_events_seq SET next_seq = 1 WHERE id = 0;  -- reset without removing the sentinel row","handlingStrategy":"validation","validationCode":"var seq int64\nerr := db.QueryRow(\"SELECT next_seq FROM bd_events_seq WHERE id = 0\").Scan(&seq)\nif errors.Is(err, sql.ErrNoRows) {\n    _, _ = db.Exec(\"INSERT INTO bd_events_seq (id, next_seq) VALUES (0, 1)\")\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"journal: read seq counter\") {\n    return fmt.Errorf(\"journal seq row missing or unreadable; re-run migrations: %w\", err)\n}","preventionTips":["Never manually DELETE from or drop bd_events_seq.","Verify the id=0 sentinel row after restores/imports.","Run migrations as a startup step.","Avoid external jobs that truncate journal bookkeeping tables."],"tags":["storage","database","journal","sql"],"backgroundTag":"sequence-counter-read-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}