payloadcms/payload · error · Error

Migration ${migration.name} not found locally.

Error message

Migration ${migration.name} not found locally.

What it means

Thrown by `migrateReset`, which rolls back every applied migration in reverse order to fully reset the database schema. Like the down/refresh variants, it requires that each row in `payload-migrations` has a corresponding local migration file exposing a `down()` function; if any name has no file, the reset cannot proceed.

Source

Thrown at packages/drizzle/src/migrateReset.ts:38

  const migrationFiles = await readMigrationFiles({ payload })

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

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

  const req = await createLocalReq({}, payload)

  existingMigrations.reverse()

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

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

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

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Restore the missing migration file(s) from git so the local set matches the DB rows, then re-run reset.
  2. On a disposable database, prefer `payload migrate:fresh` (drop+recreate) to avoid depending on every historical `down()`.
  3. Delete orphaned rows in `payload-migrations` for files you intentionally removed, then retry reset.
  4. Double-check the adapter's migration directory is the one that originally produced these migrations.

Example fix

// before: payload migrate:reset fails on 'Migration 0003_indexes not found locally.'
// after: restore file or wipe DB
//   git checkout main -- src/migrations/0003_indexes.ts && payload migrate:reset
// or for dev:  payload migrate:fresh
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check before reset
const files = await readMigrationFiles({ payload })
const { existingMigrations } = await getMigrations({ payload })
const known = new Set(files.map(f => f.name))
if (existingMigrations.some(m => !known.has(m.name))) {
  throw new Error('Aborting reset: some applied migrations lack local files')
}
await payload.db.migrateReset()

Type guard

null

Try / catch

try {
  await payload.db.migrateReset()
} catch (err) {
  if (/not found locally/.test(String(err?.message))) {
    payload.logger.warn(`Reset blocked by drift; run migrate:fresh to recreate the DB.`)
  }
  throw err
}

Prevention

When it happens

Trigger: Calling `payload migrate:reset` (or the adapter's `migrateReset`) when the `payload-migrations` table contains a row whose migration file is absent from the migration directory read by `readMigrationFiles`.

Common situations: Resetting a long-lived DB whose older migration files were archived/deleted; branch switching that leaves orphaned DB rows; renamed migrations without a corresponding DB-row update; wrong `migrationDir`.

Related errors


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