payloadcms/payload · error · APIError

Collection ${collectionSlug} was not found in R2 Storage opt

Error message

Collection ${collectionSlug} was not found in R2 Storage options

What it means

Thrown inside the R2 multipart-upload handler after it indexes the storage adapter's own `collections` option map (collections[collectionSlug]). Unlike error 380, this checks the R2 adapter configuration, not Payload's global collection registry. A bare APIError (HTTP 500) signals the collection exists in Payload but was never wired into this storage adapter.

Source

Thrown at packages/storage-r2/src/handleMultiPartUpload.ts:46

    : Boolean(req.user)
}

// Adapted from https://developers.cloudflare.com/r2/api/workers/workers-multipart-usage/
export const getHandleMultiPartUpload =
  ({
    access = defaultR2ClientUploadsAccess,
    bucket,
    collections,
    useCompositePrefixes = false,
  }: Args): PayloadHandler =>
  async (req) => {
    const params = Object.fromEntries(req.searchParams) as R2StorageMultipartUploadHandlerParams
    const collectionSlug = params.collection
    const filetype = params.fileType

    const collectionConfig = collections[collectionSlug]
    if (!collectionConfig) {
      throw new APIError(`Collection ${collectionSlug} was not found in R2 Storage options`)
    }

    if (!(await access({ collectionSlug, req }))) {
      throw new Forbidden(req.t)
    }

    const collectionPrefix = (typeof collectionConfig === 'object' && collectionConfig.prefix) || ''
    const { fileKey, sanitizedFilename } = await resolveSignedURLKey({
      collectionPrefix,
      collectionSlug,
      docPrefix: params.docPrefix ?? undefined,
      filename: params.fileName,
      req,
      useCompositePrefixes,
    })

    const multipartId = params.multipartId
    const multipartKey = params.multipartKey

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Add the missing collection slug to the R2 adapter's `collections` option (e.g. collections: { media: { prefix: 'media' } }).
  2. Confirm the adapter is instantiated with the same collection slugs that perform multipart uploads.
  3. If the collection should not use R2 multipart uploads, prevent the client from requesting that endpoint for it.

Example fix

// before
const r2Adapter = new R2Storage({ bucket, collections: { media: { prefix: 'media' } } })
// client requests ?collection=avatars → throws

// after
const r2Adapter = new R2Storage({
  bucket,
  collections: {
    media: { prefix: 'media' },
    avatars: { prefix: 'avatars' },
  },
})
Defensive patterns

Strategy: validation

Validate before calling

function isConfiguredForR2(slug: string, collections: Record<string, unknown>): boolean {
  return slug in collections
}

// guard before the request
if (!isConfiguredForR2(collectionSlug, r2AdapterCollections)) {
  throw new Error(`Collection '${collectionSlug}' is not configured on the R2 adapter`)
}

Type guard

function collectionHasR2Config<T extends Record<string, unknown>>(
  slug: string,
  collections: T,
): slug is keyof T & string {
  return slug in collections
}

Try / catch

try {
  await initiateMultipartUpload({ collection: slug })
} catch (err) {
  if (err instanceof APIError && /R2 Storage options/i.test(err.message)) {
    // prompt operator to add the collection to the R2 adapter config
  }
  throw err
}

Prevention

When it happens

Trigger: The collection slug resolves in req.payload.collections but not in the R2StorageOptions.collections map passed to the adapter — i.e. the collection is registered but the R2 adapter does not have an entry (prefix/options) for it.

Common situations: A new upload-enabled collection was added to Payload config but the developer forgot to add it to the R2 adapter's `collections` option; the adapter was mounted on only a subset of upload collections; slug renamed in one place but not the adapter config.

Related errors


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