dolt_backup patrol queries dolt_remotes instead of dolt_backups — backups silently never run
Summary
The daemon's dolt_backup patrol enumerates backup-eligible databases by querying dolt_remotes, but dolt backup add writes to dolt_backups — a different system table. The query returns empty, the patrol logs no databases with backup remotes found, and no backup ever runs.
This is fail-open: the log line reads like a normal no-op, nothing escalates, and gt reports no error. A town can run for days believing it is backed up. Ours did — 46 hours, five databases, zero backups, no warning.
Repro
Any town whose databases were configured with dolt backup add:
$ cd <town>/.dolt-data/hq
$ dolt backup -v
backup_export file:///Users/me/gt/.beads/backup {}
$ dolt sql -q 'SELECT name FROM dolt_remotes'
(empty)
$ dolt sql -q 'SELECT name FROM dolt_backups'
+---------------+
| name |
+---------------+
| backup_export |
+---------------+Then watch the daemon:
$ grep dolt_backup daemon/daemon.log | tail -3
2026/09/13 08:28:29 dolt_backup: no databases with backup remotes found
2026/09/13 09:49:00 dolt_backup: no databases with backup remotes found
2026/09/13 10:20:37 dolt_backup: no databases with backup remotes foundAll five databases in this town had backup_export configured. The patrol found none of them, on every cycle, for days.
Cause
The gt binary contains the literal query:
USE `%s`; SELECT name FROM dolt_remotes LIMIT 1Dolt keeps remotes and backups in separate tables. dolt backup add <name> <url> populates dolt_backups; dolt remote add populates dolt_remotes. A database can have a backup configured and no remote at all — which is the normal shape for a backup-only setup, and is what gt's own docs steer users toward.
Suggested fix
Enumerate from dolt_backups (or union both) when selecting databases for the backup patrol.
Separately, and arguably more important than the query itself: no databases with backup remotes found should not be a routine INFO line. If a town has databases and none are backup-eligible, that is a misconfiguration worth surfacing, not a quiet skip. Backups are the one subsystem whose whole purpose is to be there after everything else has failed; it should be the loudest thing in the daemon, not the quietest.
Related, same fail-open shape in the same subsystem
jsonl_git_backup: git repo /Users/me/.dolt-archive/git does not exist, skippingA missing archive directory is also treated as a skip rather than a misconfiguration to surface. Same consequence: silent, indefinite, no backups. Both paths would benefit from escalating instead of logging and continuing.
This is the same family as #4632 (gt hook serialising a failed read as Nothing on hook with rc=0) — an error rendered as a normal empty result.
Environment
- gastown v1.1.0 (Homebrew)
- beads 1.2.2 (Homebrew)
- dolt 2.3.3
- macOS (Darwin 25.5.0, arm64)
- 5 databases, all with
backup_exporttargets configured
Workaround
Calling DOLT_BACKUP('sync', ...) per database directly works and is unaffected by the enumeration bug:
cd <town>/.dolt-data/<db>
dolt sql -q "CALL DOLT_BACKUP('sync','backup_export')"We now run this hourly from launchd, logging per target and exiting nonzero on failure, and verified it by restoring a backup into a scratch directory and comparing row counts and content against live.
Source: gastownhall/gastown