payloadcms/payload · error · APIError

The collection with slug ${String(collectionSlug)} can't be

Error message

The collection with slug ${String(collectionSlug)} can't be found. Count Operation.

What it means

Thrown by the Local API `count` wrapper in packages/payload/src/collections/operations/local/count.ts:74 when the `collection` slug passed to `payload.count(...)` does not resolve to a registered collection in `payload.collections`. Because no HTTP status is supplied to APIError, it surfaces as HTTP 500 even though the cause is a bad client argument. It fires before `createLocalReq`, so no request context or access check runs.

Source

Thrown at packages/payload/src/collections/operations/local/count.ts:74

  where?: Where
}

export async function countLocal<TSlug extends CollectionSlug>(
  payload: Payload,
  options: CountOptions<TSlug>,
): Promise<{ totalDocs: number }> {
  const {
    collection: collectionSlug,
    disableErrors,
    overrideAccess = true,
    trash = false,
    where,
  } = options

  const collection = payload.collections[collectionSlug]

  if (!collection) {
    throw new APIError(
      `The collection with slug ${String(collectionSlug)} can't be found. Count Operation.`,
    )
  }

  return countOperation<TSlug>({
    collection,
    disableErrors,
    overrideAccess,
    req: await createLocalReq(options as CreateLocalReqOptions, payload),
    trash,
    where,
  })
}

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Open the collection config file and copy the exact `slug:` value, then pass that string to `collection`.
  2. Log `Object.keys(payload.collections)` right before the call to confirm the slug is registered at runtime.
  3. Ensure `await payload.init()` has resolved before any `payload.count(...)` call (especially in standalone scripts, workers, or tests).
  4. Remove any `as CollectionSlug` / `as any` casts on dynamic strings and let the literal-union type catch typos at compile time.

Example fix

// before
await payload.count({ collection: 'post' as CollectionSlug }) // typo: real slug is 'posts'

// after
await payload.count({ collection: 'posts' })
Defensive patterns

Strategy: validation

Validate before calling

// Run before payload.count(...)
function assertCollectionSlug(payload: Payload, slug: string): void {
  if (!(slug in payload.collections)) {
    throw new Error(
      `Unknown collection slug '${slug}'. Registered: ${Object.keys(payload.collections).join(', ')}`,
    )
  }
}

assertCollectionSlug(payload, 'posts')
await payload.count({ collection: 'posts' })

Type guard

import type { Collection, CollectionSlug, Payload } from 'payload'

const slugIsRegistered = (
  payload: Payload,
  slug: string,
): slug is CollectionSlug => slug in (payload.collections as Record<string, Collection>)

// usage
const slug: string = getInputSlug()
if (slugIsRegistered(payload, slug)) {
  await payload.count({ collection: slug }) // slug narrowed to CollectionSlug
} else {
  // handle unknown slug
}

Try / catch

try {
  await payload.count({ collection: slug })
} catch (err) {
  if (err instanceof APIError && /can't be found\. Count Operation/.test(err.message)) {
    // slug not registered — fix the caller, do not retry blindly
  } else {
    throw err
  }
}

Prevention

When it happens

Trigger: Calling `payload.count({ collection: 'post' })` where the registered slug is `'posts'` (singular vs plural), calling count with a dynamically-built slug string that does not exist, or invoking count before `payload.init()` has finished registering collections.

Common situations: Renaming a collection's `slug` in config but forgetting to update seed/migration scripts; importing a stale slug constant; casting an arbitrary string with `as CollectionSlug` to satisfy TypeScript while bypassing the literal-union check; running a script that uses a different Payload instance than the one whose config was loaded.

Related errors


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