-
Notifications
You must be signed in to change notification settings - Fork 3k
Description
Describe the Bug
Media file uploads fail with a 500 error in Cloudflare Workers (preview/production) when using beforeValidate
or beforeChange
hooks on upload-enabled collections. The same code works perfectly in local development.
Link to the code that reproduces this issue
https://github.com/heatloss/chimera-d1/tree/bug-test-1
Reproduction Steps
Reproduction Steps for Payload CMS Workers Hook Bug
Quick Reproduction (5 minutes)
1. Create from Official Template
npx create-payload-app@latest my-test-app
Select:
- Template: Cloudflare D1
- Package manager: pnpm
2. Add Custom ID Hook
Edit src/collections/Media.ts
and add the custom ID field with hook:
import type { CollectionConfig } from 'payload'
export const Media: CollectionConfig = {
slug: 'media',
access: {
read: () => true,
},
fields: [
{
name: 'id',
type: 'text',
required: true,
admin: {
hidden: true,
},
hooks: {
beforeValidate: [
({ value, operation }) => {
if (operation === 'create' && !value) {
return crypto.randomUUID()
}
return value
}
]
}
},
{
name: 'alt',
type: 'text',
required: true,
},
],
upload: {
crop: false,
focalPoint: false,
},
}
3. Test Local Dev (Works)
pnpm dev
Navigate to http://localhost:3000/admin/collections/media and upload a file.
Result: ✅ Upload succeeds
4. Test Workers Preview (Fails)
pnpm wrangler login
pnpm preview
Navigate to the preview URL /admin/collections/media
and upload a file.
Result: ❌ POST /api/media 500 Internal Server Error
Expected vs Actual
- Expected: Hooks work in both dev and production
- Actual: Hooks work in dev, fail with 500 error in Workers
Verification Test
To verify this is hook-related, remove the hooks
section from the id
field and change required: true
to required: false
:
{
name: 'id',
type: 'text',
required: false, // Changed
admin: {
hidden: true,
},
// hooks removed
}
Rebuild and test preview again:
Result: ✅ Upload succeeds (without custom ID generation)
Full Reproduction Repository
For a complete working example with all testing steps documented, see:
[Your GitHub repo URL here if you create one]
Or follow the steps above starting from the official Payload Cloudflare template.
Which area(s) are affected? (Select all that apply)
area: core, area: templates
Environment Info
Binaries:
Node: 22.18.0
npm: 10.9.3
pnpm: 10.18.0
Relevant Packages:
payload: 3.58.0
next: 15.5.4
@payloadcms/graphql: 3.58.0
@payloadcms/next/utilities: 3.58.0
@payloadcms/plugin-cloud-storage: 3.58.0
@payloadcms/richtext-lexical: 3.58.0
@payloadcms/db-d1-sqlite: 3.58.0
@payloadcms/storage-r2: 3.58.0
@opennextjs/cloudflare: 1.10.1
react: 19.1.0
react-dom: 19.1.0
wrangler: 4.42.2
Operating System:
Platform: darwin (macOS)
Arch: arm64
Node: 22.18.0
Deployment Environment:
- Local dev: Node.js (works ✅)
- Production: Cloudflare Workers via OpenNext (fails ❌)
- Database: D1 (remote mode)
- Storage: R2