payloadcms/payload · error · Error
Cannot provide both collectionSlug and globalSlug
Error message
Cannot provide both collectionSlug and globalSlug
What it means
localizeStatus treats collectionSlug and globalSlug as mutually exclusive because it must pick the right versions collection and config lookup. Thrown when both are supplied at once.
Source
Thrown at packages/db-mongodb/src/predefinedMigrations/migrateLocalizeStatus.ts:85
await cleanupSnapshotDocuments({ connection, entitySlug: global.slug, payload, session })
}
payload.logger.info({ msg: 'localize-status migration completed successfully' })
}
/**
* Converts version._status (and the main document _status) from a scalar string to a
* per-locale object for a single collection or global.
*/
export async function localizeStatus(args: LocalizeStatusArgs): Promise<void> {
const { collectionSlug, globalSlug, payload, req, session } = args
if (!collectionSlug && !globalSlug) {
throw new Error('Either collectionSlug or globalSlug must be provided')
}
if (collectionSlug && globalSlug) {
throw new Error('Cannot provide both collectionSlug and globalSlug')
}
const entitySlug = collectionSlug || globalSlug
// MongoDB collection names are case-insensitive and stored as lowercase
const versionsCollection = `_${entitySlug}_versions`.toLowerCase()
if (!payload.config.localization) {
throw new Error('Localization is not enabled in payload config')
}
// Check if versions are enabled on this collection/global
let entityConfig
if (collectionSlug) {
const collection = payload.config.collections.find((c) => c.slug === collectionSlug)
if (collection) {
entityConfig = collection
}
} else if (globalSlug) {View on GitHub (pinned to 00c58b35c0)
Solutions
- Pass exactly one identifier: collectionSlug OR globalSlug, never both.
- Loop collections and globals in separate branches, each calling localizeStatus with only the relevant slug.
- Add an assertion/log in your caller to confirm only one is set before invoking.
- Use the migrateLocalizeStatus() orchestrator which handles the split correctly.
Example fix
// before
await localizeStatus({
collectionSlug: 'posts',
globalSlug: 'header',
payload,
req,
})
// after — two separate calls
await localizeStatus({ collectionSlug: 'posts', payload, req })
await localizeStatus({ globalSlug: 'header', payload, req }) Defensive patterns
Strategy: validation
Validate before calling
function assertMutuallyExclusive(args: { collectionSlug?: string; globalSlug?: string }) {
if (args.collectionSlug && args.globalSlug) {
throw new Error('Pass collectionSlug OR globalSlug, not both')
}
} Type guard
function isExactlyOneEntity(a: { collectionSlug?: string; globalSlug?: string }): boolean {
return Boolean(a.collectionSlug) !== Boolean(a.globalSlug)
} Prevention
- Loop collections and globals in separate branches.
- Never merge both slug fields into one args object.
- Use the orchestrator to avoid manual arg construction.
When it happens
Trigger: Calling localizeStatus() with both collectionSlug and globalSlug set, e.g. from a custom loop that iterates both lists and accidentally merges the arguments.
Common situations: A custom migration script building args dynamically that ends up populating both fields; copy-paste error when adding a new entity.
Related errors
- Either collectionSlug or globalSlug must be provided
- ${collectionSlug ? 'Collection' : 'Global'} not found: ${col
- Localization is not enabled in payload config
- Migration aborted: version._status field not found or has un
- Either collection or globalSlug must be passed.
AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12).
Data as JSON: /api/errors/81a6645be3f6506a.
Report an issue: GitHub.