{"record":{"id":"f49c475d00905ff3","repo":"payloadcms/payload","slug":"either-collection-or-globalslug-must-be-passed-f49c47","errorCode":null,"errorMessage":"Either collection or globalSlug must be passed.","messagePattern":"Either collection or globalSlug must be passed\\.","errorType":"http","errorClass":"APIError","httpStatus":500,"severity":"error","filePath":"packages/drizzle/src/deleteVersions.ts","lineNumber":32,"sourceCode":"  this: DrizzleAdapter,\n  { collection: collectionSlug, globalSlug, locale, req, where: where },\n) {\n  let tableName: string\n  let fields: FlattenedField[]\n\n  if (globalSlug) {\n    const globalConfig = this.payload.globals.config.find(({ slug }) => slug === globalSlug)\n    tableName = this.tableNameMap.get(`_${toSnakeCase(globalSlug)}${this.versionsSuffix}`)\n    fields = buildVersionGlobalFields(this.payload.config, globalConfig, true)\n  } else if (collectionSlug) {\n    const collectionConfig: SanitizedCollectionConfig =\n      this.payload.collections[collectionSlug].config\n    tableName = this.tableNameMap.get(\n      `_${toSnakeCase(collectionConfig.slug)}${this.versionsSuffix}`,\n    )\n    fields = buildVersionCollectionFields(this.payload.config, collectionConfig, true)\n  } else {\n    throw new APIError('Either collection or globalSlug must be passed.')\n  }\n\n  const { docs } = await findMany({\n    adapter: this,\n    fields,\n    joins: false,\n    limit: 0,\n    locale,\n    page: 1,\n    pagination: false,\n    req,\n    tableName,\n    where,\n  })\n\n  const ids = []\n\n  docs.forEach((doc) => {","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/payloadcms/payload/blob/00c58b35c0ed348ddc22daabf467b139727214fd/packages/drizzle/src/deleteVersions.ts#L14-L50","documentation":"Thrown by the Drizzle `deleteVersions` when neither `collectionSlug` nor `globalSlug` is supplied — both the global branch and the collection branch are skipped, so the method cannot determine which versions table to delete from and aborts. This is primarily an internal-contract violation since `deleteVersions` is an adapter method, not a public API.","triggerScenarios":"An internal/programmatic call to the adapter's `deleteVersions` without specifying a target slug — e.g. a custom adapter subclass, a fork calling private methods, or a regression in Payload internals that drops the slug.","commonSituations":"Custom adapter subclassing that overrides/wraps deleteVersions; calling adapter internals directly instead of the public API; an upgrade regression that stopped forwarding the slug.","solutions":["Always pass `collectionSlug` or `globalSlug` when calling `deleteVersions`.","Prefer the public API (`payload.deleteVersions({ collection })` / `{ global }`) over adapter internals.","If hitting this via a public API path, report it as a bug with a reproduction.","In custom subclasses, forward both slugs from the caller."],"exampleFix":"// before\nawait adapter.deleteVersions({ req }) // no slug\n// after\nawait payload.deleteVersions({ collection: 'posts', id, req })","handlingStrategy":"validation","validationCode":"function assertDeleteVersionsTarget(args) {\n  if (!args.collectionSlug && !args.globalSlug)\n    throw new Error('deleteVersions requires collectionSlug or globalSlug')\n}","typeGuard":"const hasDeleteTarget = (a) => Boolean(a?.collectionSlug) || Boolean(a?.globalSlug)","tryCatchPattern":"try { await adapter.deleteVersions(args) }\ncatch (e) { if (/Either collection or globalSlug/.test(e.message)) throw new Error('Caller must specify a target') else throw e }","preventionTips":["Call the public API (payload.deleteVersions) rather than adapter internals.","In adapter subclasses, always forward collectionSlug/globalSlug.","Treat hitting this via a public path as a bug to report with a repro."],"tags":["drizzle","internal","versions","config"],"backgroundTag":null,"analyzedSha":"00c58b35c0ed348ddc22daabf467b139727214fd","analyzedAt":"2026-08-12T20:45:03.758Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}