gastownhall/beads · error
recording aux rekey sentinel
Error message
recording aux rekey sentinel: %w
What it means
Before the first UPDATE of the rekey rewrite, rekeyAuxRowIDsPending records an in-progress sentinel in local_metadata (setAuxRekeyInProgress) so a crash mid-rewrite leaves proof to resume on the next pass instead of recording the completion marker over partially re-keyed rows. This error wraps failure to write that sentinel (the CREATE TABLE IF NOT EXISTS plus REPLACE INTO), and aborts the pass before any table is rewritten.
Solutions
- Unwrap to the driver error; if it is the CREATE step see 'ensuring local_metadata', if REPLACE, grant INSERT/UPDATE on local_metadata.
- Retry MigrateUp — nothing was rewritten, so the pass starts cleanly.
- Verify local_metadata exists and is writable (bd doctor / EnsureIgnoredTables).
- Check Dolt backend health: disk space, replication status, and open transactions.
Example fix
-- before -- migration user lacks write access to local_metadata -- after GRANT INSERT, UPDATE, DELETE, CREATE ON mydb.* TO 'beads'@'%'; FLUSH PRIVILEGES;
Defensive patterns
Strategy: retry
Validate before calling
var canWrite int
_ = db.QueryRow(`SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLE_PRIVILEGES
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'local_metadata' AND PRIVILEGE_TYPE = 'INSERT'`).Scan(&canWrite)
if canCreateTableFails || canWrite == 0 { return errors.New("cannot write rekey sentinel to local_metadata") } Try / catch
if err := migrateUp(ctx, db); err != nil {
if strings.Contains(err.Error(), "recording aux rekey sentinel") {
// sentinel write failed BEFORE any table rewrite; retry is clean
return retryWithBackoff(func() error { return migrateUp(ctx, db) })
}
return err
} Prevention
- Grant the migration user INSERT/UPDATE/DELETE on local_metadata plus CREATE on the schema.
- Verify disk space and Dolt replication health before long migrations.
- Do not mark the pass complete manually — without the sentinel, a crash mid-rewrite would leave ambiguous state.
- Re-run MigrateUp after fixing privileges; no tables were touched when this error fired.
When it happens
Trigger: The pass is about to run (marker pending, resume decision made) and the sentinel writes fail: CREATE TABLE fails (no DDL privilege, read-only, conflict) or REPLACE INTO fails (INSERT privilege missing, table corrupt, connection drop).
Common situations: Migration user with read/write on data tables but not DDL or write on local_metadata; a fresh clone where local_metadata creation hits a privilege wall; disk-full or replication lag on the Dolt backend.
Related errors
- reading aux rekey sentinel
- %s: %w
- backfill custom tables
- checking dirty tables against pending ignored migrations
- checking dirty tables against pending migrations
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/a3625a7d71c2d0ec.
Report an issue: GitHub.
Appendix: source
Thrown at internal/storage/schema/aux_row_id_backfill.go:247
return false, nil
}
resume, err := auxRekeyResumePending(ctx, db, pass.sentinelKey)
if err != nil {
return false, fmt.Errorf("reading aux rekey sentinel: %w", err)
}
// The fresh-clone skip must not fire on a lineage whose previous pass
// crashed mid-rekey: that pass already advanced the main cursor past the
// shipped version, but its sentinel proves the rewrite never finished
// (bd-578h9.16).
if mainVersionBefore >= pass.shippedMainVersion && !resume {
return false, nil
}
// Sentinel before the first UPDATE: a crash anywhere in the rewrite
// leaves it set, so the next pass resumes (the rewrite is idempotent)
// instead of recording the marker over partially re-keyed rows.
if err := setAuxRekeyInProgress(ctx, db, pass.sentinelKey); err != nil {
return false, fmt.Errorf("recording aux rekey sentinel: %w", err)
}
wrote := false
for _, t := range auxRekeyTables {
w, err := rekeyAuxRowTable(ctx, db, t)
wrote = wrote || w
if err != nil {
return wrote, fmt.Errorf("%s: %w", t.name, err)
}
}
if err := clearAuxRekeyInProgress(ctx, db, pass.sentinelKey); err != nil {
return wrote, fmt.Errorf("clearing aux rekey sentinel: %w", err)
}
return wrote, nil
}
// rekeyAuxRowTable re-derives the ids of one table. The whole table is grouped
// by content digest; each digest's rows take the deterministic ids forView on GitHub (pinned to 71377f2769)