payloadcms/payload · error · Error

Migration not found locally.

Error message

Migration ${migration.name} not found locally.

What it means

Thrown by `migrateDown` (`payload migrate:rollback`) when the `payload-migrations` table records a migration whose name has no matching file in the local migrations directory. Rollback must execute the migration's `down` function, which only exists in the file — so a missing file aborts the rollback. Typically the migration file was deleted, renamed, or the deployed code is behind the DB.

Solutions

  1. Restore the missing migration file from version control so its `down()` is available.
  2. If the rollback is intentionally impossible, manually remove the row from the `payload-migrations` collection/table.
  3. Keep migration files immutable once applied — never delete applied migrations.

Example fix

# before: migration file deleted, rollback fails
payload migrate:rollback
# after: restore the file, then rollback
git checkout HEAD -- src/migrations/2024_01_01_init.ts
payload migrate:rollback
Defensive patterns

Strategy: validation

Validate before calling

import { readdir } from 'fs/promises'
const local = new Set((await readdir('./src/migrations')).map(stripExt))
const recorded = await payload.find({ collection: 'payload-migrations', limit: 0 })
const missing = recorded.docs.filter((m) => !local.has(m.name))
if (missing.length) throw new Error(`Missing local migration files: ${missing.map((m) => m.name).join(', ')}`)

Try / catch

try {
  await payload.db.migrateDown()
} catch (err) {
  if (/not found locally/.test((err as Error).message)) {
    // restore the file from git or remove the stray DB row, then retry
  }
  throw err
}

Prevention

When it happens

Trigger: Running `payload migrate:rollback` after deleting a migration file from `src/migrations`; deploying code that no longer ships an older migration that the DB still records; renaming a migration file without re-syncing the DB.

Common situations: Squashing/cleaning up migration files mid-project; CI/CD deploy that pruned old migrations; switching branches where the migration set differs.

Related errors


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

Appendix: source

Thrown at packages/payload/src/database/migrations/migrateDown.ts:32

  const { existingMigrations, latestBatch } = await getMigrations({
    payload,
  })

  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 latestBatchMigrations = existingMigrations.filter(({ batch }) => batch === latestBatch)

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

    const start = Date.now()
    const req = await createLocalReq({}, payload)

    try {
      payload.logger.info({ msg: `Migrating down: ${migrationFile.name}` })
      await initTransaction(req)
      const session = payload.db.sessions?.[await req.transactionID!]
      await migrationFile.down({ payload, req, session })
      payload.logger.info({
        msg: `Migrated down:  ${migrationFile.name} (${Date.now() - start}ms)`,
      })
      // Waiting for implementation here
      await payload.delete({
        id: migration.id!,
        collection: 'payload-migrations',
        req,

View on GitHub (pinned to 00c58b35c0)