payloadcms/payload · error · APIError

Collection ${args.collection.config.slug} has disabled bulk

Error message

Collection ${args.collection.config.slug} has disabled bulk delete

What it means

`deleteOperation` checks `disableBulkDelete` on the collection config; if true and the caller did not pass `overrideAccess`, it throws `APIError` (403). This is a deliberate safety guard preventing accidental mass deletion on collections flagged as bulk-delete-protected.

Source

Thrown at packages/payload/src/collections/operations/delete.ts:57

  overrideAccess?: boolean
  overrideLock?: boolean
  populate?: PopulateType
  req: PayloadRequest
  showHiddenFields?: boolean
  trash?: boolean
  where: Where
} & Pick<FindOptions<string, SelectType>, 'select'>

export const deleteOperation = async <
  TSlug extends CollectionSlug,
  TSelect extends SelectFromCollectionSlug<TSlug>,
>(
  incomingArgs: Arguments,
): Promise<BulkOperationResult<TSlug, TSelect>> => {
  let args = incomingArgs

  if (args.collection.config.disableBulkDelete && !args.overrideAccess) {
    throw new APIError(`Collection ${args.collection.config.slug} has disabled bulk delete`, 403)
  }

  try {
    const shouldCommit = !args.disableTransaction && (await initTransaction(args.req))
    // /////////////////////////////////////
    // beforeOperation - Collection
    // /////////////////////////////////////

    args = await buildBeforeOperation({
      args,
      collection: args.collection.config,
      operation: 'delete',
      overrideAccess: args.overrideAccess!,
    })

    const {
      collection: { config: collectionConfig },
      depth,

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Delete by ID (`payload.deleteByID`) instead of bulk delete, if appropriate.
  2. If this is legitimate privileged work, pass `overrideAccess: true`.
  3. Reconsider whether `disableBulkDelete` should remain true for this collection.

Example fix

// before
await payload.delete({ collection: 'orders', where: { status: { equals: 'archived' } } })
// after (privileged migration only)
await payload.delete({ collection: 'orders', where: { status: { equals: 'archived' } }, overrideAccess: true })
Defensive patterns

Strategy: validation

Validate before calling

function canBulkDelete(collectionConfig, overrideAccess = false) {
  return !collectionConfig.disableBulkDelete || overrideAccess
}

Type guard

function bulkDeleteAllowed(cfg, overrideAccess): boolean {
  return overrideAccess || !cfg.disableBulkDelete
}

Try / catch

try {
  await payload.delete({ collection, where })
} catch (e) {
  if (e?.statusCode === 403 && /disabled bulk delete/.test(e.message)) {
    // fall back to per-ID deletes
  } else throw e
}

Prevention

When it happens

Trigger: Calling `payload.delete({ collection, where })` on a collection configured with `disableBulkDelete: true`, without `overrideAccess: true`.

Common situations: A cleanup/migration script targeting a protected collection; a UI bulk-action on a guarded collection; forgetting `overrideAccess` in privileged server code.

Related errors


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