payloadcms/payload · error · Error
Migration aborted: version._status field not found or has un
Error message
Migration aborted: version._status field not found or has unexpected format in ${versionsCollection}. This migration should only run on schemas that have NOT yet been migrated to per-locale status. What it means
Before migrating, localizeStatus samples one version document and requires version._status to be a plain string (the pre-migration shape). If version._status is missing, an array, or otherwise non-string, the migration aborts to avoid corrupting data. This protects against running on already-migrated or schema-drifted data.
Source
Thrown at packages/db-mongodb/src/predefinedMigrations/migrateLocalizeStatus.ts:168
// Check if _status is already localized
if (
sampleDoc.version?._status &&
typeof sampleDoc.version._status === 'object' &&
!Array.isArray(sampleDoc.version._status)
) {
payload.logger.info({
msg: 'version._status is already localized, migration already completed',
})
return
}
// Validate that version._status exists and is a string
if (
!sampleDoc.version ||
typeof sampleDoc.version._status !== 'string' ||
Array.isArray(sampleDoc.version._status)
) {
throw new Error(
`Migration aborted: version._status field not found or has unexpected format in ${versionsCollection}. ` +
`This migration should only run on schemas that have NOT yet been migrated to per-locale status.`,
)
}
payload.logger.info({ msg: 'Fetching all version documents...' })
// Get all versions, sorted chronologically
const allVersions = await connection
.collection(versionsCollection)
.find({}, { session })
.sort({ createdAt: 1, parent: 1 })
.toArray()
payload.logger.info({ msg: `Found ${allVersions.length} version documents` })
// Transform MongoDB documents to VersionRecord format
const versionRecords: VersionRecord[] = allVersions.map((doc: any) => ({View on GitHub (pinned to 00c58b35c0)
Solutions
- If the migration already ran, no action is needed — verify a sample doc shows version._status as an object.
- If documents legitimately lack version._status (no drafts), backfill them (e.g. set version._status='draft') or exclude the entity from the migration.
- Inspect a sample doc: `db._<slug>_versions.findOne()` and confirm the shape before retrying.
- Restore from backup and run the migration once on clean pre-migration data if the collection is in a mixed/half-converted state.
Example fix
// diagnostics — inspect before deciding
// mongosh
db._posts_versions.findOne({}, { 'version._status': 1 })
// if half-converted (mixed string + object), backfill to a clean pre-state or
// restore from backup, then run migrateLocalizeStatus once. Defensive patterns
Strategy: validation
Validate before calling
// Sample the versions collection before invoking the migration
async function assertPreMigrationShape(db: any, versionsCollection: string) {
const sample = await db.collection(versionsCollection).findOne({})
if (!sample) return // nothing to migrate
if (typeof sample.version?._status !== 'string') {
throw new Error(`${versionsCollection} is not in pre-migration shape (version._status is ${typeof sample.version?._status})`)
}
} Type guard
function isPreMigrationStatus(sample: unknown): sample is { version: { _status: string } } {
return typeof sample === 'object' && sample !== null &&
typeof (sample as any)?.version?._status === 'string'
} Try / catch
try {
await localizeStatus({ collectionSlug, payload, req })
} catch (e) {
if (e instanceof Error && e.message.includes('Migration aborted')) {
payload.logger.warn('localize-status already applied or data not in pre-migration shape — skipping')
return
}
throw e
} Prevention
- Run the migration exactly once on clean pre-migration data.
- Backfill or exclude entities whose versions legitimately lack version._status.
- Sample a document before running to confirm the expected shape.
- Back up the database before running schema-shifting migrations.
When it happens
Trigger: Running localizeStatus on a versions collection whose sample document lacks version._status (e.g. drafts never produced a status), where _status was already converted to an object (re-running the migration), or where custom code wrote an array/non-string into version._status.
Common situations: Re-running the localize-status migration after it already completed; documents created by a custom import that omitted version._status; partial prior migration left the collection half-converted; versions enabled without drafts so _status was never written.
Related errors
- Either collectionSlug or globalSlug must be provided
- Cannot provide both collectionSlug and globalSlug
- Localization is not enabled in payload config
- ${collectionSlug ? 'Collection' : 'Global'} not found: ${col
- Either collection or globalSlug must be passed.
AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12).
Data as JSON: /api/errors/823d94b2d802e8f4.
Report an issue: GitHub.