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
- Rename the class so it ends in exactly 13 digits, e.g. `class AddUserTable1700000000000`. Use the current `Date.now()` value.
- Regenerate the migration with the CLI so naming stays consistent.
- 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
- Always generate migrations with the CLI so names carry `Date.now()`.
- Add a precheck (above) in your test setup so a bad name fails fast.
- Never rename a migration class without preserving the 13-digit suffix.
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
- No migration ${lastTimeExecutedMigration.name} was found in
- Model ID is required
- Invalid delegate sub-agent tool name "${name}": must start w
- ${toolName} requires resumeSubAgent and cancelSubAgent to be
- ${toolName} was registered without a runSubAgent callback, a
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/28b3913dd948a63d.
Report an issue: GitHub.