n8n-io/n8n · error · TypeORMError

${migrationClassName} migration name is wrong. Migration cla

Error message

${migrationClassName} migration name is wrong. Migration class name should have a JavaScript timestamp appended.

What it means

TypeORM orders migrations by parsing the trailing 13 characters of each migration class name as a millisecond timestamp (`parseInt(name.substr(-13), 10)`). If the class name does not end in a 13-digit numeric timestamp the parse yields NaN and TypeORM throws, because it cannot determine execution order. This runs inside `getMigrations()`, invoked by run/show/generate/revert.

Source

Thrown at packages/@n8n/typeorm/src/migration/MigrationExecutor.ts:531

			.getRawMany();
		return migrationsRaw.map((migrationRaw) => {
			return new Migration(
				parseInt(migrationRaw['id']),
				parseInt(migrationRaw['timestamp']),
				migrationRaw['name'],
			);
		});
	}

	/**
	 * Gets all migrations that setup for this connection.
	 */
	protected getMigrations(): Migration[] {
		const migrations = this.connection.migrations.map((migration) => {
			const migrationClassName = migration.name || (migration.constructor as any).name;
			const migrationTimestamp = parseInt(migrationClassName.substr(-13), 10);
			if (!migrationTimestamp || isNaN(migrationTimestamp)) {
				throw new TypeORMError(
					`${migrationClassName} migration name is wrong. Migration class name should have a JavaScript timestamp appended.`,
				);
			}

			return new Migration(undefined, migrationTimestamp, migrationClassName, migration);
		});

		this.checkForDuplicateMigrations(migrations);

		// sort them by timestamp
		return migrations.sort((a, b) => a.timestamp - b.timestamp);
	}

	protected checkForDuplicateMigrations(migrations: Migration[]) {
		const migrationNames = migrations.map((migration) => migration.name);
		const duplicates = Array.from(
			new Set(
				migrationNames.filter(

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Rename the class so it ends in exactly 13 digits, e.g. `class AddUserTable1700000000000`. Use the current `Date.now()` value.
  2. Regenerate the migration with the CLI so naming stays consistent.
  3. Audit every entry in the `migrations` array and fix any whose name fails `/\d{13}$/`.

Example fix

// before
class AddUserTable extends Migration { async up() {} }

// after
class AddUserTable1700000000000 extends Migration { async up() {} }
Defensive patterns

Strategy: validation

Validate before calling

// Validate every configured migration class name ends in a 13-digit timestamp
const NAME_RE = /\d{13}$/;
for (const m of dataSource.migrations) {
  const name = m.name || (m as any).constructor.name;
  if (!NAME_RE.test(name) || Number.isNaN(parseInt(name.slice(-13), 10))) {
    throw new Error(`Migration ${name} must end in a 13-digit timestamp`);
  }
}

Prevention

When it happens

Trigger: Naming a migration class by hand, e.g. `class InitialSchema extends Migration` instead of `class InitialSchema1700000000000`. Renaming a migration and dropping the numeric suffix. Copying a migration file and changing the class name without preserving the 13-digit suffix.

Common situations: Hand-authoring a migration instead of using the generator (`migration:generate`), which names the file/class with `Date.now()`. A linter/formatter stripping trailing digits. Importing migrations from a barrel that re-exports under a different name.

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/28b3913dd948a63d. Report an issue: GitHub.