toeverything/AFFiNE · critical · Error

Invalid migration name: ${migration.name}

Error message

Invalid migration name: ${migration.name}

What it means

Thrown by `collectMigrations` when a migration module's `name` does not end in a run of digits (regex `/([\d]+)$/`). The trailing number is parsed as the migration's run `order`; without it, `Number(undefined)` yields `NaN` and the loader aborts. A plain `Error` (no error code), thrown during module-load/CLI bootstrap.

Source

Thrown at packages/backend/server/src/data/commands/run.ts:21

import { PrismaClient } from '@prisma/client';
import { once } from 'lodash-es';

import * as migrationImports from '../migrations';

interface Migration {
  name: string;
  always?: boolean;
  up: (db: PrismaClient, injector: ModuleRef) => Promise<void>;
  down: (db: PrismaClient, injector: ModuleRef) => Promise<void>;
  order: number;
}

export const collectMigrations = once(() => {
  const migrations = Object.values(migrationImports).map(migration => {
    const order = Number(migration.name.match(/([\d]+)$/)?.[1]);

    if (Number.isNaN(order)) {
      throw new Error(`Invalid migration name: ${migration.name}`);
    }

    return {
      name: migration.name,
      // @ts-expect-error optional
      always: migration.always,
      up: migration.up,
      down: migration.down,
      order,
    };
  }) as Migration[];

  return migrations.sort((a, b) => a.order - b.order);
});

@Injectable()
export class RunCommand {
  logger = new Logger(RunCommand.name);

View on GitHub (pinned to 26c515e050)

Solutions

  1. Rename the offending migration file so it ends in digits — conventionally a millisecond timestamp prefix, e.g. `1766000000000-my-migration.ts`.
  2. Match the existing naming pattern in `packages/backend/server/src/data/migrations/` (all are `<digits>-slug.ts`).
  3. Re-run the migration command after renaming to confirm `collectMigrations` no longer throws.
  4. Update any scaffolding/generator template so new migrations always get a numeric suffix.

Example fix

// before: src/data/migrations/add-indexes.ts
//   (loader throws: Invalid migration name: add-indexes)

// after: rename to
//   src/data/migrations/1766000000000-add-indexes.ts
Defensive patterns

Strategy: validation

Validate before calling

// Enforce naming convention in a generator/scaffold
function migrationFilename(slug) {
  const ts = Date.now();
  return `${ts}-${slug}.ts`; // always ends in digits before .ts
}

Type guard

function hasNumericSuffix(name) {
  return /\d+$/.test(name);
}

Prevention

When it happens

Trigger: Adding a migration file whose name lacks a trailing numeric suffix — e.g. `add-indexes.ts` instead of `1766000000000-add-indexes.ts`. The loader iterates every exported migration module at startup and fails on the first malformed name.

Common situations: New migration added without following the `timestamp-slug.ts` naming convention; renaming a migration file and dropping the numeric prefix; migration file generated by a scaffold that did not append the timestamp.

Related errors


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