toeverything/AFFiNE · error · Error
Migration ${name} has not been executed.
Error message
Migration ${name} has not been executed. What it means
Thrown by RevertCommand.execute(name) in packages/backend/server/src/data/commands/run.ts:160 when reverting a data migration. Before calling migration.down(), the command looks up a finished record in the dataMigration table (written by RunCommand.runMigration on success). If no record exists, the migration was never run (or never finished), so there is nothing to revert. This is a plain Error, not a UserFriendlyError, so it surfaces as an internal server error to API callers.
Source
Thrown at packages/backend/server/src/data/commands/run.ts:160
const migration = migrations.find(m => m.name === name);
if (!migration) {
this.logger.error('Available migration names:');
migrations.forEach(m => {
this.logger.error(` - ${m.name}`);
});
throw new Error(`Unknown migration name: ${name}.`);
}
const record = await this.db.dataMigration.findFirst({
where: {
name: migration.name,
},
});
if (!record) {
throw new Error(`Migration ${name} has not been executed.`);
}
try {
this.logger.log(`Reverting ${name}...`);
await migration.down(this.db, this.injector);
this.logger.log('Done reverting');
} catch (e) {
this.logger.error(`Failed to revert data migration ${name}`, e);
}
await this.db.dataMigration.delete({
where: {
id: record.id,
},
});
}
}
View on GitHub (pinned to 26c515e050)
Solutions
- Run the forward migrations first (RunCommand.execute) so a dataMigration record exists, then revert.
- Verify state in the DB: SELECT * FROM dataMigration WHERE name = '<name>'; if absent, the migration was never completed.
- If the migration genuinely was never applied and you want its down() to run anyway, call migration.down() directly rather than via RevertCommand.
- Check server logs for a prior 'Failed to run data migration' entry (run.ts:112) indicating the up() failed and rolled back.
Example fix
// before
await revertCommand.execute('addUserFlags1700000000000');
// after
const ran = await db.dataMigration.findFirst({ where: { name: 'addUserFlags1700000000000' } });
if (!ran) {
logger.warn('Migration was never executed; nothing to revert.');
} else {
await revertCommand.execute('addUserFlags1700000000000');
} Defensive patterns
Strategy: validation
Validate before calling
const record = await db.dataMigration.findFirst({ where: { name: migrationName } });
if (!record) {
logger.warn(`Skip revert: ${migrationName} was never executed.`);
return;
}
await revertCommand.execute(migrationName); Type guard
const isExecutedMigration = (r: { id: string; finishedAt: Date | null } | null): r is { id: string; finishedAt: Date | null } =>
r !== null; Prevention
- Always run forward migrations (RunCommand.execute) before invoking RevertCommand.
- Treat the absence of a dataMigration row as 'nothing to revert', not an error.
- Inspect SELECT * FROM dataMigration WHERE name=? before reverting in production.
When it happens
Trigger: Invoking the data-migration revert flow (RevertCommand.execute) with a migration name that has no corresponding row in the dataMigration table. The name resolves to a known migration file (otherwise the 'Unknown migration name' error at run.ts:150 fires first), but findFirst by name returns null.
Common situations: Running revert on a fresh database where 'run' was never executed; reverting a migration whose up() failed midway (RunCommand.runMigration deletes the record on failure at run.ts:106); reverting after a manual DB wipe of the dataMigration table; passing a migration name that exists in code but was added after the current DB state.
Related errors
- Invalid migration name: ${migration.name}
- Unknown migration name: ${name}.
- A migration name is required
- DatabaseBlockError
- Invalid rowId
AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12).
Data as JSON: /api/errors/c51cb2d723ce8c93.
Report an issue: GitHub.