gastownhall/beads · error
db: IssueSQLRepository.GetEpicsEligibleForClosure: %w
Error message
db: IssueSQLRepository.GetEpicsEligibleForClosure: %w
What it means
Wraps a failure from issueops.GetEpicsEligibleForClosureInTx, which scans open epic IDs and checks dependency/child status to decide which epics may close. The wrapper only adds repository context — the real cause (SQL error, scan error) is in the wrapped chain. This runs during epic auto-closure flows.
Source
Thrown at internal/storage/domain/db/issue.go:1209
events, err := issueops.GetEventsInTx(ctx, r.runner, id, limit)
if err != nil {
return nil, fmt.Errorf("db: IssueSQLRepository.IterEvents: %w", err)
}
return storage.NewSliceIter(events), nil
}
func (r *issueSQLRepositoryImpl) GetStaleIssues(ctx context.Context, filter types.StaleFilter) ([]*types.Issue, error) {
out, err := issueops.GetStaleIssuesInTx(ctx, r.runner, filter)
if err != nil {
return nil, fmt.Errorf("db: IssueSQLRepository.GetStaleIssues: %w", err)
}
return out, nil
}
func (r *issueSQLRepositoryImpl) GetEpicsEligibleForClosure(ctx context.Context) ([]*types.EpicStatus, error) {
out, err := issueops.GetEpicsEligibleForClosureInTx(ctx, r.runner)
if err != nil {
return nil, fmt.Errorf("db: IssueSQLRepository.GetEpicsEligibleForClosure: %w", err)
}
return out, nil
}
func (r *issueSQLRepositoryImpl) UnclaimIssue(ctx context.Context, id, actor string, force bool) error {
if err := issueops.UnclaimIssueInTx(ctx, r.runner, id, actor, force); err != nil {
return fmt.Errorf("db: IssueSQLRepository.UnclaimIssue: %w", err)
}
return nil
}
// UnclaimIssueIfAssignee runs the classic compare-and-swap release against this
// runner. Like UnclaimIssue it takes no IssueTableOpts: issueops routes the
// write to the issues or wisps tables from the row itself, so a wisp's claim is
// released against the wisp tables on both backends. The mismatch verdict
// (storage.ErrAssigneeMismatch, nothing written) is produced by the shared
// helper, not restated here.
func (r *issueSQLRepositoryImpl) UnclaimIssueIfAssignee(ctx context.Context, id, actor, expectedAssignee string) error {View on GitHub (pinned to 71377f2769)
Solutions
- Inspect the wrapped cause in the error chain for the exact SQL failure.
- Verify issues/dependencies tables exist with current schema (run migrations / bd doctor).
- Retry on transient connection errors; the operation is read-only and safe to re-run.
- Reduce scope/tune timeouts if the sweep times out with many epics.
Example fix
// before
out, err := repo.GetEpicsEligibleForClosure(ctx)
if err != nil { log.Fatal(err) }
// after
out, err := repo.GetEpicsEligibleForClosure(ctx)
if err != nil {
log.Printf("epic closure sweep skipped: %v", err) // read-only, safe to retry later
return
} Defensive patterns
Strategy: retry
Validate before calling
// cheap pre-check: are there open epics at all?
var n int
_ = db.QueryRow("SELECT COUNT(*) FROM issues WHERE issue_type='epic' AND status != 'closed'").Scan(&n)
if n == 0 { return } // skip sweep Try / catch
out, err := repo.GetEpicsEligibleForClosure(ctx)
if err != nil {
if isTransientDBErr(err) { scheduleRetry(err); return }
log.Printf("epic closure sweep failed: %v", err)
return
} Prevention
- Treat the sweep as idempotent/read-only and retry on failure.
- Run migrations before enabling epic auto-closure.
- Avoid overlapping sweeps with a scheduler lock.
- Alert on the wrapped cause, not just the wrapper message.
When it happens
Trigger: Any error inside GetEpicsEligibleForClosureInTx: the initial 'SELECT id FROM issues WHERE issue_type='epic'' scan fails, an IN-clause query over child issues fails, or optional blocked-table probing errors.
Common situations: Schema drift (issues table missing expected columns), table-not-exist on a partial migration, connection failure during the multi-query closure sweep, or query timeout with large epic sets.
Related errors
- ErrQuery
- failed to get federation peer: %w
- failed to list federation peers: %w
- failed to get comments: %w
- failed to check issue_counter for prefix %q: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/ff9f3cd7832a68b1.
Report an issue: GitHub.