gastownhall/beads · error
journal: compute retain-days floor: %w
Error message
journal: compute retain-days floor: %w
What it means
In the retain-days pruning strategy, the cutoff time is converted to a floor seq via EventsPruneDaysFloorQuery (MIN(seq) over rows older than cutoff). This error wraps a Scan failure of that query. ErrNoRows and a NULL MIN (no matching rows) are both treated as 'no bound', so this is always a real driver error.
Source
Thrown at internal/storage/issueops/journal_prune.go:398
var ceil int64
scanErr := tx.QueryRowContext(ctx, EventsPruneRowsCeilQuery(), retainRows).Scan(&ceil)
if errors.Is(scanErr, sql.ErrNoRows) {
return 0, false, nil
}
if scanErr != nil {
return 0, false, fmt.Errorf("journal: compute retain-rows floor: %w", scanErr)
}
return ceil, true, nil
}
readDaysFloor := func(cutoff time.Time) (int64, bool, error) {
// MIN over no matching rows yields one NULL row, not ErrNoRows.
var floorSeq sql.NullInt64
scanErr := tx.QueryRowContext(ctx, EventsPruneDaysFloorQuery(), cutoff).Scan(&floorSeq)
if errors.Is(scanErr, sql.ErrNoRows) {
return 0, false, nil
}
if scanErr != nil {
return 0, false, fmt.Errorf("journal: compute retain-days floor: %w", scanErr)
}
if !floorSeq.Valid {
return 0, false, nil
}
return floorSeq.Int64, true, nil
}
return readRowsCeil, readDaysFloor
}
// PruneEventsInTx deletes journal rows with seq below before, honoring the
// retain-days and retain-rows floors (0 disables a floor), and returns the
// number of rows deleted. It runs inside the caller's transaction.
func PruneEventsInTx(ctx context.Context, tx DBTX, before int64, retainDays, retainRows int, now time.Time) (int64, error) {
readRowsCeil, readDaysFloor := eventsPruneFloorReadersInTx(ctx, tx, retainRows)
where, args, skip, err := ComputeEventsPruneWhere(before, retainDays, retainRows, now, readRowsCeil, readDaysFloor)
if err != nil {
return 0, err
}View on GitHub (pinned to 71377f2769)
Solutions
- Retry; transient connection or lock errors are common wrapped causes.
- Verify migrations created bd_events_journal with a normalized ts column (CAST(ts AS CHAR) normalization exists for driver variance).
- Check the Dolt/driver version supports the date comparison used by EventsPruneDaysFloorQuery; upgrade if not.
- Inspect server logs for the exact underlying SQL error.
Example fix
// before
store.ComputeEventsAutoPruneBoundInTx(ctx, tx, PruneOpts{RetainDays: 0}) // nonsensical cutoff
// after
store.ComputeEventsAutoPruneBoundInTx(ctx, tx, PruneOpts{RetainDays: 30}) // sane retention window Defensive patterns
Strategy: validation
Validate before calling
if opts.RetainDays <= 0 { return errors.New("RetainDays must be positive") }
if _, err := db.Query("SELECT MIN(seq) FROM bd_events_journal WHERE ts < NOW()"); err != nil {
return fmt.Errorf("day-floor query unsupported on this driver: %w", err)
} Try / catch
if err != nil && strings.Contains(err.Error(), "journal: compute retain-days floor") {
if isDialectError(err) { return fallbackToRetainRowsPolicy(opts) }
return err
} Prevention
- Use a driver/Dolt version tested against the app's date-comparison SQL.
- Sanity-check retention settings before pruning.
- Prefer retain-rows policy if your driver has date-comparison quirks.
- Run a dry-run bound computation before enabling scheduled pruning.
When it happens
Trigger: ComputeEventsAutoPruneBoundInTx with a RetainDays policy failing at the floor query: type mismatch comparing the ts column against the cutoff parameter, missing table, connection failure, or driver incompatibility with the date comparison expression.
Common situations: Driver/dialect mismatch where the cutoff time cannot be bound or compared (e.g. older Dolt not supporting the DATETIME comparison form); clock/cutoff values far outside stored range triggering edge-case casts; pre-migration DB.
Related errors
- journal: compute retain-rows floor: %w
- journal: prune below %d: %w
- journal: advance seq counter: %w
- journal: read seq counter: %w
- journal: read seq counter: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/5ae4e03364d3366c.
Report an issue: GitHub.