payloadcms/payload · critical · Error

No previous migration schema file found! A prior migration f

Error message

No previous migration schema file found! A prior migration from v2 is required to migrate to v3.

What it means

Thrown by the Postgres v2→v3 migration when no prior Drizzle snapshot JSON file is found in the migration directory. The v2→v3 migration diffs the previous snapshot against the current schema to generate the column moves (relationships/uploads out of the join table), so without a baseline snapshot there is nothing to diff and the migration cannot run.

Source

Thrown at packages/drizzle/src/postgres/predefinedMigrations/v2-v3/index.ts:64

 * @param req
 */
export const migratePostgresV2toV3 = async ({ debug, payload, req }: Args) => {
  const adapter = payload.db as unknown as BasePostgresAdapter
  const dir = payload.db.migrationDir

  // get the drizzle migrateUpSQL from drizzle using the last schema
  const { generateDrizzleJson, generateMigration, upSnapshot } = adapter.requireDrizzleKit()
  const drizzleJsonAfter = generateDrizzleJson(adapter.schema) as DrizzleSnapshotJSON

  // Get the previous migration snapshot
  const previousSnapshot = fs
    .readdirSync(dir)
    .filter((file) => file.endsWith('.json') && !file.endsWith('relationships_v2_v3.json'))
    .sort()
    .reverse()?.[0]

  if (!previousSnapshot) {
    throw new Error(
      `No previous migration schema file found! A prior migration from v2 is required to migrate to v3.`,
    )
  }

  let drizzleJsonBefore = JSON.parse(
    fs.readFileSync(`${dir}/${previousSnapshot}`, 'utf8'),
  ) as DrizzleSnapshotJSON

  if (upSnapshot && drizzleJsonBefore.version < drizzleJsonAfter.version) {
    drizzleJsonBefore = upSnapshot(drizzleJsonBefore)
  }

  const generatedSQL = await generateMigration(drizzleJsonBefore, drizzleJsonAfter)

  if (!generatedSQL.length) {
    payload.logger.info(`No schema changes needed.`)
    process.exit(0)
  }

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Ensure the project has a prior v2-era migration with its generated `.json` snapshot in the migration directory before running the v3 upgrade.
  2. Generate a baseline migration on the v2 codebase first (`payload migrate:create`), commit the snapshot, then run the v2→v3 migration.
  3. Confirm `payload.db.migrationDir` resolves to the directory containing the historical snapshots.

Example fix

// before: migrationDir has no *.json snapshot -> throws
// after: on the v2 branch, generate the baseline first
//   payload migrate:create baseline
// commit the produced .json snapshot, then run the v2->v3 migration
Defensive patterns

Strategy: validation

Validate before calling

import fs from 'fs'
const snapshot = fs.readdirSync(payload.db.migrationDir)
  .filter(f => f.endsWith('.json') && !f.endsWith('relationships_v2_v3.json'))
  .sort().reverse()[0]
if (!snapshot) {
  throw new Error('No v2 snapshot found; generate baseline migrations on the v2 branch first.')
}
await migratePostgresV2toV3({ payload })

Type guard

null

Try / catch

try {
  await migratePostgresV2toV3({ payload })
} catch (err) {
  if (/No previous migration schema file found/.test(String(err?.message))) {
    payload.logger.error('Generate a v2 baseline migration snapshot before upgrading.')
  }
  throw err
}

Prevention

When it happens

Trigger: Invoking `migratePostgresV2toV3` in a project whose migration directory contains no `.json` snapshot files (other than `relationships_v2_v3.json`, which is explicitly excluded), e.g. a project that never generated v2 migrations, or whose migration directory is empty/misconfigured.

Common situations: Attempting v2→v3 on a fresh project with no migration history; migration directory cleared or pointing at the wrong path; project that used `push`/auto-sync instead of generated migrations; the only JSON present is the v2-v3 relationships file.

Related errors


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