{"record":{"id":"23eb3a30e3c65264","repo":"payloadcms/payload","slug":"this-collection-is-not-an-upload-collection-col","errorCode":null,"errorMessage":"This collection is not an upload collection: ${collection.config.slug}","messagePattern":"This collection is not an upload collection: (.+?)","errorType":"http","errorClass":"APIError","httpStatus":400,"severity":"error","filePath":"packages/payload/src/uploads/endpoints/getFile.ts","lineNumber":25,"sourceCode":"\nimport type { PayloadHandler } from '../../config/types.js'\n\nimport { APIError } from '../../errors/APIError.js'\nimport { checkFileAccess } from '../../uploads/checkFileAccess.js'\nimport { streamFile } from '../../uploads/fetchAPI-stream-file/index.js'\nimport { getFileTypeFallback } from '../../uploads/getFileTypeFallback.js'\nimport { parseRangeHeader } from '../../uploads/parseRangeHeader.js'\nimport { getRequestCollection } from '../../utilities/getRequestEntity.js'\nimport { headersWithCors } from '../../utilities/headersWithCors.js'\n\nexport const getFileHandler: PayloadHandler = async (req) => {\n  const collection = getRequestCollection(req)\n\n  const filename = req.routeParams?.filename as string\n  const prefix = req.searchParams?.get('prefix') ?? undefined\n\n  if (!collection.config.upload) {\n    throw new APIError(\n      `This collection is not an upload collection: ${collection.config.slug}`,\n      httpStatus.BAD_REQUEST,\n    )\n  }\n\n  const accessResult = (await checkFileAccess({\n    collection,\n    filename,\n    prefix,\n    req,\n  }))!\n\n  if (accessResult instanceof Response) {\n    return accessResult\n  }\n\n  if (collection.config.upload.handlers?.length) {\n    let customResponse: null | Response | void = null","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/payloadcms/payload/blob/00c58b35c0ed348ddc22daabf467b139727214fd/packages/payload/src/uploads/endpoints/getFile.ts#L7-L43","documentation":"APIError (HTTP 400) thrown by the getFileHandler when the resolved collection has no `upload` property in its config. The GET /api/:collection/file/:filename route only serves upload collections; any other collection slug is rejected before filename/access processing.","triggerScenarios":"GET request to /api/<slug>/file/<filename> (or /api/<slug>/id/<id>/<filename>) where <slug> resolves to a collection whose config lacks an `upload` block — e.g. a plain global, a blog-posts collection defined without upload, or a typo in the slug.","commonSituations":"Wrong collection slug in a URL (typo, stale frontend link); accessing the file route of a collection that stores file metadata but uses an external storage plugin without the upload field; misconfigured reverse proxy routing file requests to the wrong collection; frontend building URLs from a non-upload collection.","solutions":["Verify the slug in the URL matches a collection defined with an `upload` block in your Payload config.","Add `upload: { staticDir: '...' }` to that collection's config if files should be served from it.","Check the frontend URL builder to ensure it only emits file URLs for actual upload collections.","Confirm the route prefix matches your config.admin.user or custom routes if you customized them."],"exampleFix":"// before — collection without upload\n{ slug: 'docs', fields: [ { name: 'file', type: 'text' } ] }\n// after — make it an upload collection\n{ slug: 'docs', upload: { staticDir: 'docs' }, fields: [ { name: 'file', type: 'upload' } ] }","handlingStrategy":"type-guard","validationCode":"const UPLOAD_SLUGS = Object.entries(payload.config.collections)\n  .filter(([, c]) => Boolean(c.upload))\n  .map(([slug]) => slug)\nfunction isUploadSlug(slug: string): boolean {\n  return UPLOAD_SLUGS.includes(slug)\n}\n// before building a file URL:\nif (!isUploadSlug(slug)) throw new Error(`${slug} is not an upload collection`)","typeGuard":"const isUploadCollectionConfig = (c: { upload?: unknown }): boolean =>\n  Boolean(c && typeof c === 'object' && 'upload' in c && c.upload)","tryCatchPattern":"try {\n  const res = await fetch(`/api/${slug}/file/${filename}`)\n  if (res.status === 400) {\n    const body = await res.json()\n    if (/not an upload collection/.test(body.errors?.[0]?.message ?? '')) {\n      console.error('Wrong collection slug — not an upload collection')\n    }\n  }\n} catch (e) { /* network */ }","preventionTips":["Centralize file-URL construction in a helper that only emits for upload collections.","Type your collection slugs as a union of known upload slugs.","Document which collections are upload collections.","Add a CI check that file URLs are only built against collections with upload config."],"tags":["upload","api","config","routing"],"backgroundTag":null,"analyzedSha":"00c58b35c0ed348ddc22daabf467b139727214fd","analyzedAt":"2026-08-12T20:45:03.758Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}