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

  1. Run the forward migrations first (RunCommand.execute) so a dataMigration record exists, then revert.
  2. Verify state in the DB: SELECT * FROM dataMigration WHERE name = '<name>'; if absent, the migration was never completed.
  3. If the migration genuinely was never applied and you want its down() to run anyway, call migration.down() directly rather than via RevertCommand.
  4. 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

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


AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12). Data as JSON: /api/errors/c51cb2d723ce8c93. Report an issue: GitHub.