Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

plugin-cloud-storage: upload with a focal point set before first save fails when the adapter returns a new filename (e.g. Vercel Blob addRandomSuffix)

Open
#18,804 1 comment 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

@AmineBenzaazaa is already working on this.

Since Oct 16, 2026.

  • #18805 by @AmineBenzaazaa — open

Assessment

Difficulty
3/5
Estimated time
1-2 days
Newbie friendliness
35/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Stale
Domain
api, backend

Research direction

Read packages/plugin-cloud-storage/src/hooks/afterChange.ts and packages/plugin-cloud-storage/src/hooks/generateFileData.ts, focusing on the nested update and upload edit parsing described in the issue. Reproduce with a Vercel Blob adapter using addRandomSuffix: true and a focal point set before the first save. Done means the create succeeds without fetching the pre-suffix filename; an open linked pull request already addresses this issue.

Written by the indexing model from the issue text.

Description

area: uploads Bug plugin: cloud-storage
Describe the Bug

Creating a document in an upload collection fails with a 500 ("An unknown error has occurred" in the admin) when both of these are true:

  • the storage adapter's handleUpload returns metadata such as a new filename. @payloadcms/storage-vercel-blob does this when addRandomSuffix: true.
  • the editor sets a focal point before the first save, so the admin sends ?uploadEdits[focalPoint][x]=…&[y]=….

Server log:

There was an error while uploading files corresponding to the collection media with filename IMG_9210 2.jpeg:
There was a problem while uploading the file. Failed to fetch file from https://<store>.public.blob.vercel-storage.com/IMG_9210%202.jpeg
  at hooks.afterChange.adapter …

Cause

In plugin-cloud-storage/src/hooks/afterChange.ts, when handleUpload returns metadata, the hook stores it with a nested req.payload.update({ …, req }) on the same req. Before that call it clears req.file and req.payloadUploadSizes, but leaves req.query.uploadEdits in place.

Inside the nested update, generateFileData → parseUploadEditsFromReqOrIncomingData reads req.query.uploadEdits.focalPoint again. That value came from the query string, so x and y are strings ("37"). shouldReupload compares them strictly with the stored numbers (37), finds them unequal, and treats it as a focal-point edit. It then calls getExternalFile on originalDoc.url, which still points at the pre-suffix filename. That object doesn't exist, so the fetch 404s, the error is thrown, and the create rolls back.

Dragging the file in without setting a focal point works, because no uploadEdits is sent.

Suggested fix (either one works)

  • In afterChange.ts, also clear the consumed edits before the nested update, next to req.file = undefined: if (req.query) delete req.query.uploadEdits
  • In generateFileData.ts, convert to numbers in shouldReupload (Number(uploadEdits.focalPoint.x) === fileData.focalX), so query-string values compare correctly.

Workaround we shipped: a collection beforeOperation hook that deletes req.query.uploadEdits when operation === 'update' && req.context?.skipCloudStorage.

Link to the code that reproduces this issue

Our project repo is private, but the Local API snippet below reproduces it in any project with the Vercel Blob adapter configured with addRandomSuffix: true. Happy to put together a standalone repro repo if that would help.

Reproduction Steps
  1. Configure vercelBlobStorage({ collections: { media: true }, addRandomSuffix: true, token }) on an upload collection with focalPoint: true (the default).
  2. In the admin, create a new media doc, choose a file, and move the focal point away from the center.
  3. Save. The request returns a 500 and the server logs Failed to fetch file from …/<unsuffixed filename>.

The same thing happens through the Local API:

await payload.create({
  collection: 'media',
  data: {},
  file: { data, mimetype: 'image/jpeg', name: 'test image.jpeg', size: data.length },
  req: { query: { uploadEdits: { focalPoint: { x: '37', y: '62' } } } },
})

With numeric x/y equal to the stored values, it succeeds.

Which area(s) are affected?

plugin: cloud-storage, area: uploads

Environment Info
payload: 3.90.2 (code unchanged in plugin-cloud-storage 3.91.0)
@payloadcms/storage-vercel-blob: 3.90.2
@vercel/blob: 2.3.1
next: 16.3.6
node: 24
db: @payloadcms/db-postgres
Dominant language
TypeScript
Stars
45.5k
Forks
4.3k
Avg merge
1d 19h
Merged PRs (30d)
295

Getting set up

Open in Codespaces

Starts the project's dev container in your browser, under your own GitHub account.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from payloadcms/payload

All issues in payloadcms/payload

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.