{"record":{"id":"d8000653b21457bd","repo":"gastownhall/beads","slug":"journal-close-derived-is-blocked-from-s-w","errorCode":null,"errorMessage":"journal: close derived is_blocked from %s: %w","messagePattern":"journal: close derived is_blocked from (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/storage/issueops/journal.go","lineNumber":249,"sourceCode":"\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\treturn nil, fmt.Errorf(\"journal: snapshot derived is_blocked from %s: %w\", target.table, err)\n\t\t\t}\n\t\t\tfor rows.Next() {\n\t\t\t\tvar id string\n\t\t\t\tvar blocked int\n\t\t\t\tif err := rows.Scan(&id, &blocked); err != nil {\n\t\t\t\t\t_ = rows.Close()\n\t\t\t\t\treturn nil, fmt.Errorf(\"journal: scan derived is_blocked from %s: %w\", target.table, err)\n\t\t\t\t}\n\t\t\t\tsnapshot[blockedJournalKey{table: target.table, id: id}] = blocked != 0\n\t\t\t}\n\t\t\tif err := rows.Err(); err != nil {\n\t\t\t\t_ = rows.Close()\n\t\t\t\treturn nil, fmt.Errorf(\"journal: iterate derived is_blocked from %s: %w\", target.table, err)\n\t\t\t}\n\t\t\tif err := rows.Close(); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"journal: close derived is_blocked from %s: %w\", target.table, err)\n\t\t\t}\n\t\t}\n\t}\n\treturn snapshot, nil\n}\n\n// recordBlockedJournalChanges compares the stable post-maintenance state with\n// the captured state and journals only beads whose derived is_blocked value\n// actually changed. The emitted update carries the complete post-mutation\n// snapshot, allowing a cursor consumer to stay correct without graph queries.\nfunc recordBlockedJournalChanges(\n\tctx context.Context,\n\ttx DBTX,\n\tbefore blockedJournalSnapshot,\n\tissueIDs, wispIDs []string,\n) error {\n\tif before == nil {\n\t\treturn nil","sourceCodeStart":231,"sourceCodeEnd":267,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/journal.go#L231-L267","documentation":"rows.Close() returned an error after completing the is_blocked snapshot query. Rare; indicates the driver could not cleanly release the result set, which can leave the connection in a bad state, so the transaction fails fast.","triggerScenarios":"The deferred-style explicit rows.Close() after rows.Err() returned non-nil, typically due to an already-broken connection or driver-level cleanup failure.","commonSituations":"Connection invalidated mid-query; driver-specific close failures under contention or timeouts.","solutions":["Inspect the wrapped error; it usually masks an earlier connection problem","Retry the transaction on a fresh connection","Check connection-pool health (max lifetime, stale connections)","Upgrade the SQL driver if close errors recur"],"exampleFix":"null","handlingStrategy":"retry","validationCode":"if err := db.Ping(); err != nil { /* refresh pool before the transaction */ }","typeGuard":"null","tryCatchPattern":"snap, err := captureBlockedJournalSnapshot(ctx, tx)\nif err != nil {\n  if isCloseErr(err) { tx.Rollback(); return retryWithFreshTx(ctx) }\n  return err\n}","preventionTips":["Set ConnMaxLifetime below server idle-kill thresholds","Avoid holding transactions across slow operations","Upgrade the SQL driver if close errors recur"],"tags":["sql","rows-close","journal","resource-cleanup"],"backgroundTag":"sql-rows-close-error","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}