louislam/uptime-kuma · error · Error
Aggregate table migration is already in progress
Error message
Aggregate table migration is already in progress
What it means
migrateAggregateTable() reads the Settings key 'migrateAggregateTableState'. The value 'migrating' indicates a previous run started the aggregate-table migration but never set it to 'migrated', which happens when the process was killed mid-migration. Rather than risk two concurrent migrations corrupting aggregate data, Uptime Kuma refuses to start. The warning log just above ('…or it was interrupted') tells you the same thing.
Solutions
- Simply start the server again — if the prior migration actually completed but failed to flip the flag, a clean retry will set 'migrated'.
- If it genuinely crashed mid-migration and the data is intact, the safest recovery is to set the flag manually: run the SQLite shell (or MariaDB client) and UPDATE the setting, e.g. `UPDATE setting SET value='migrated' WHERE key='migrateAggregateTableState';`, after confirming the aggregate tables are fully populated.
- For 2.0.0-dev users who want to skip the migration entirely, set env `SET_MIGRATE_AGGREGATE_TABLE_TO_TRUE=1` on the next start (see database.js:858).
- If the migration keeps failing, check disk space and the migration status server (port/hostname args to migrateAggregateTable) for the underlying error.
Example fix
# before — stuck in 'migrating' after a crash # (server refuses to boot) # after — reset the flag in SQLite and restart sqlite3 ./data/kuma.db "UPDATE setting SET value='migrated' WHERE key='migrateAggregateTableState';" npm run start
Defensive patterns
Strategy: fallback
Validate before calling
// Pre-flight: detect the stuck 'migrating' state before boot
const { Database } = require("./server/database");
const { Settings } = require("./server/settings");
async function migrationIsStuck() {
await Database.connect(false, false, true);
const s = await Settings.get("migrateAggregateTableState");
return s === "migrating";
} Try / catch
try {
await Database.migrateAggregateTable(port, hostname);
} catch (e) {
if (/already in progress/.test(e.message)) {
// either retry once (the prior run may have finished) or, if you are certain
// the data is consistent, set migrateAggregateTableState=migrated and restart
log.error("startup", e.message);
process.exit(1);
}
throw e;
} Prevention
- Avoid hard-killing the process during a major version upgrade; let it shut down cleanly.
- Monitor disk and memory during the 1.x -> 2.x migration so the OOM killer does not interrupt it.
- Keep the SET_MIGRATE_AGGREGATE_TABLE_TO_TRUE=1 escape hatch documented for dev instances.
When it happens
Trigger: The server was SIGKILLed, OOM-killed, or lost power during the startup aggregate-table migration (introduced for the 2.x data model). On next boot the setting still reads 'migrating' and boot aborts.
Common situations: Hard restarts during an upgrade from 1.x to 2.x; containers killed past their grace period; low-memory hosts where the OOM killer terminates node mid-migration.
Related errors
- Both and _FILE are set. Please use only one.
- Failed to read _FILE at
- Invalid db-config.json, type must be a string
- Unknown Database type
- Database connection/query failed
AI-assisted analysis of louislam/uptime-kuma@6b5ea01557 (2026-08-12).
Data as JSON: /api/errors/718c84473c85487b.
Report an issue: GitHub.
Appendix: source
Thrown at server/database.js:875
// Add a setting for 2.0.0-dev users to skip this migration
if (process.env.SET_MIGRATE_AGGREGATE_TABLE_TO_TRUE === "1") {
log.warn(
"db",
"SET_MIGRATE_AGGREGATE_TABLE_TO_TRUE is set to 1, skipping aggregate table migration forever (for 2.0.0-dev users)"
);
await Settings.set("migrateAggregateTableState", "migrated");
}
let migrateState = await Settings.get("migrateAggregateTableState");
// Skip if already migrated
// If it is migrating, it possibly means the migration was interrupted, or the migration is in progress
if (migrateState === "migrated") {
log.debug("db", "Migrated aggregate table already, skip");
return;
} else if (migrateState === "migrating") {
log.warn("db", "Aggregate table migration is already in progress, or it was interrupted");
throw new Error("Aggregate table migration is already in progress");
}
/**
* Start migration server for displaying the migration status
* @type {SimpleMigrationServer}
*/
let migrationServer;
let msg;
if (port) {
migrationServer = new SimpleMigrationServer();
await migrationServer.start(port, hostname);
}
log.info("db", "Migrating Aggregate Table");
log.info("db", "Getting list of unique monitors");
View on GitHub (pinned to 6b5ea01557)