payloadcms/payload · error · Error

Either collectionSlug or globalSlug must be provided

Error message

Either collectionSlug or globalSlug must be provided

What it means

Argument-contract error from the `migratePostgresLocalizeStatus` predefined migration: the function requires exactly one target entity, so `collectionSlug` and `globalSlug` cannot both be omitted. With neither supplied there is nothing to localize, so the migration refuses to guess.

Source

Thrown at packages/drizzle/src/postgres/predefinedMigrations/localize-status/index.ts:23

import { migrateMainCollectionStatus } from './migrateMainCollection.js'
import { migrateMainGlobalStatus } from './migrateMainGlobal.js'

export type LocalizeStatusArgs = {
  collectionSlug?: string
  db: any
  globalSlug?: string
  payload: Payload
  req?: any
  sql: any
}

export async function migratePostgresLocalizeStatus(args: LocalizeStatusArgs): Promise<void> {
  const { collectionSlug, db, globalSlug, payload, req, sql } = args
  const schemaName = db.schemaName ?? 'public'

  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
  // Convert camelCase slugs to snake_case and add version prefix/suffix
  const versionsTable = collectionSlug
    ? `_${toSnakeCase(collectionSlug)}_v`
    : `_${toSnakeCase(globalSlug!)}_v`
  const localesTable = `${versionsTable}_locales`

  if (!payload.config.localization) {
    throw new Error('Localization is not enabled in payload config')
  }

  // Check if versions are enabled on this collection/global

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Pass exactly one of `collectionSlug` or `globalSlug` identifying the localized, versions-enabled entity to migrate.
  2. If iterating entities, skip iterations where neither slug applies rather than calling the migration with empty args.
  3. Guard the call site with an `if (collectionSlug || globalSlug)` check.

Example fix

// before
await migratePostgresLocalizeStatus({ db, payload, req, sql })
// after
await migratePostgresLocalizeStatus({ collectionSlug: 'posts', db, payload, req, sql })
Defensive patterns

Strategy: validation

Validate before calling

function runLocalizeStatus(args) {
  const { collectionSlug, globalSlug } = args
  if (!collectionSlug && !globalSlug) {
    throw new Error('Provide collectionSlug or globalSlug')
  }
  return migratePostgresLocalizeStatus(args)
}

Type guard

const hasEntitySlug = (a): a is { collectionSlug: string } | { globalSlug: string } =>
  typeof a?.collectionSlug === 'string' || typeof a?.globalSlug === 'string'

Try / catch

null

Prevention

When it happens

Trigger: Invoking `migratePostgresLocalizeStatus({ db, payload, sql })` (or the CLI predefined-migration runner wrapping it) without passing `collectionSlug` or `globalSlug`.

Common situations: Copy-pasting the migration invocation from docs and forgetting the slug argument; building a generic loop that iterates entities but skips empty cases incorrectly; programmatic invocation with a falsy slug variable.

Related errors


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