payloadcms/payload · error · Error

Migration ${migration.name} not found locally.

Error message

Migration ${migration.name} not found locally.

What it means

Same root cause as the other 'Migration not found locally' errors, but raised by `migrateRefresh`, which rolls back ALL applied migrations (in reverse) and is typically used to re-run the full migration set during development. The adapter reads applied migrations from the `payload-migrations` table and tries to find each one's file via `readMigrationFiles`; a name with no local file aborts the refresh before any re-run can happen.

Source

Thrown at packages/drizzle/src/migrateRefresh.ts:45

  if (!existingMigrations?.length) {
    payload.logger.info({ msg: 'No migrations to rollback.' })
    return
  }

  payload.logger.info({
    msg: `Rolling back batch ${latestBatch} consisting of ${existingMigrations.length} migration(s).`,
  })

  const req = await createLocalReq({}, payload)

  // Reverse order of migrations to rollback
  existingMigrations.reverse()

  for (const migration of existingMigrations) {
    try {
      const migrationFile = migrationFiles.find((m) => m.name === migration.name)
      if (!migrationFile) {
        throw new Error(`Migration ${migration.name} not found locally.`)
      }

      payload.logger.info({ msg: `Migrating down: ${migration.name}` })
      const start = Date.now()
      await initTransaction(req)
      const db = await getTransaction(this, req)
      await migrationFile.down({ db, payload, req })
      payload.logger.info({
        msg: `Migrated down:  ${migration.name} (${Date.now() - start}ms)`,
      })

      const tableExists = await migrationTableExists(this, db)
      if (tableExists) {
        await payload.delete({
          collection: 'payload-migrations',
          req,
          where: {
            name: {

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Restore every missing migration file named in the failure from version control so the local set is a superset of the DB rows.
  2. For a throwaway dev/preview DB, clear the drift with `payload migrate:fresh` rather than refresh.
  3. Manually remove orphaned rows from `payload-migrations` for migrations you intentionally deleted, then re-run refresh.
  4. Confirm the `migrationDir` used by the adapter matches the directory the migrations were generated into.

Example fix

// before: payload migrate:refresh fails with 'Migration 0001_init not found locally.'
// after: bring the file back, or wipe the dev DB
//   git restore src/migrations/0001_init.ts && payload migrate:refresh
// or: payload migrate:fresh
Defensive patterns

Strategy: validation

Validate before calling

// Verify all DB migrations have local files before refresh
const files = await readMigrationFiles({ payload })
const { existingMigrations } = await getMigrations({ payload })
const fileNames = new Set(files.map(f => f.name))
const orphans = existingMigrations.filter(m => !fileNames.has(m.name))
if (orphans.length) {
  throw new Error(`Cannot refresh: ${orphans.map(o => o.name).join(', ')} missing locally`)
}
await payload.db.migrateRefresh()

Type guard

null

Try / catch

try {
  await payload.db.migrateRefresh()
} catch (err) {
  if (/Migration .* not found locally/.test(String(err?.message))) {
    // decide: restore files, or wipe with migrate:fresh
  }
  throw err
}

Prevention

When it happens

Trigger: Running `payload migrate:refresh` (rollback-all then migrate-up) when one or more rows in `payload-migrations` reference migration files that no longer exist in the configured migration directory.

Common situations: Migration files pruned/renamed during a refactor while the DB still records them; switching branches whose migration histories diverge; CI/preview DB seeded by a branch whose files were later removed; `migrationDir` pointing somewhere stale.

Related errors


AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12). Data as JSON: /api/errors/3b03cefbf7e3bc37. Report an issue: GitHub.