Skip to content

Conversation

mbifulco
Copy link

@mbifulco mbifulco commented Oct 18, 2025

What?

The UploadThing storage adapter had two critical bugs that prevented images from loading correctly:

  1. Missing URL field on upload: The handleUpload function only set _key and filename fields from the UploadThing API response, but not the url field. This caused newly uploaded images to have no URL in the database.

  2. Disabled generateURL hook: The disablePayloadAccessControl setting was commented out, which prevented Payload's cloud storage plugin from calling adapter.generateURL() in the afterRead hook. This caused the API to fall back to generating /api/media/file/* URLs instead of using UploadThing CDN URLs (utfs.io), making all images inaccessible.

How?

This PR includes two fixes, and a documentation change:

  1. Set URL on upload (handleUpload.ts): Add data.url = res.data?.url for both main file uploads and image size variant uploads, so newly uploaded files have the correct UploadThing CDN URL stored in the database.

  2. Enable disablePayloadAccessControl (index.ts): Uncomment the disablePayloadAccessControl: true setting when ACL is public-read. This ensures Payload calls adapter.generateURL() when serializing documents, which generates the correct UploadThing CDN URLs for existing files.

  3. Document JWT token requirement (README.md): Add documentation clarifying that this plugin requires UploadThing tokens in JWT format (starting with ey), not the sk_ secret key format. I spent a while trying to figure out why uploadThing wasn't working - their dashboard has 2 quick-copyable different formats for API key, and I was using the wrong one!

Testing

  • Verified new uploads correctly store UploadThing CDN URLs in database
  • Confirmed API responses return https://utfs.io/f/{key} URLs instead of /api/media/file/* URLs
  • Tested that images load correctly from the UploadThing CDN

Fixes: Images returning 400 errors and failing to load from /api/media/file/*

The handleUpload function was only setting _key and filename fields
from the UploadThing API response, but not the url field. This caused
uploaded images to fail loading because Payload couldn't find the
proper CDN URL.

This fix adds data.url = res.data?.url for both main file uploads
and image size variant uploads.

Fixes: Images returning 400 errors when trying to load from /api/media/file/
Closes: #[ISSUE_NUMBER]
@mbifulco mbifulco requested a review from denolfe as a code owner October 18, 2025 01:47
…ment JWT token requirement

This commit adds two critical fixes:

1. Uncomment disablePayloadAccessControl for public-read ACL
   - When disabled/undefined, Payload cloud storage plugin does not call
     adapter.generateURL() in the afterRead hook
   - Without this, Payload falls back to /api/media/file/* URLs instead
     of using the UploadThing CDN URLs (utfs.io)
   - This makes images inaccessible since files are stored on UploadThing

2. Document JWT token format requirement in README
   - UploadThing plugin requires tokens in JWT format (starting with "ey")
   - Using sk_ format tokens will cause upload failures
   - Added clear documentation to prevent this common mistake
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant