payloadcms / payloadcms/payload

File reference is not preserved on req when using local API in hook

Open
#15,975 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

area: core Bug stale status: needs-triage
Dominant language
TypeScript
Stars
44.8k
Forks
4.2k
Avg merge
2d 21h
Merged PRs (30d)
53

Description

Describe the Bug

When using the local API from a hook (for example payload.create) in an upload collection the file reference is dropped when persisting req as recommended by the documentation. e.g.:

  hooks: {
    afterChange: [
      async ({ operation, req }) => {
      if (operation === 'create') {
        await req.payload.create({
          collection: 'others',
          req, // <- Passing req here to keep context causes the issue
          data: {
            name: 'Some generated name',
          },
        });
      }
    },
    ({ req }) => {
      // Undefined if req is passed above, otherwise the file name is logged
      // This causes unexpected behaviour for users who want to use req in afterChange hooks for media collections, as they will not be able to access req.file
      // e.g. azure storage adapter silently fails here because req.file is undefined.
      console.log(req.file?.name);
    }
    ]
  }

This can lead to cases like the azure storage adapter silently failing because there is no longer a file available in the request context when the next hook in the sequence is run, as described by the simple console log above.

I have found some similar issues (either old and closed, or current) which allude to similar issues not directly with the file on the req so I suspect this is still a case of general "leaking" on the context.

I'm more than happy to take a shot at raising a fix for this one, I can see the "offending" code on local create which sets the file as undefined on req. I just don't know what the intended semantics of this are and whether it should hold onto a file on the req if one already exists?

Link to the code that reproduces this issue

https://github.com/iamscottcab/payload-file-demo

Reproduction Steps
  1. Clone repo
  2. Install deps
  3. Run the app
  4. Upload something to the media collection
  5. Note that undefined is printed when the second afterChangeHook is run on the Media collection.
  6. Comment out req in the call to payload.create in the first afterChangeHook.
  7. Upload a new file to the media collection.
  8. Note file is preserved and the file name is printed. However we now lose the request context if we need it, for example to use the user in hooks on other collections.

Expected behaviour - The file is persisted through the entire request context despite a call to payload.create on another collection that is not an upload collection.

Which area(s) are affected?

area: core

Environment Info
Binaries:
  Node: 22.13.0
  npm: N/A
  Yarn: N/A
  pnpm: N/A
Relevant Packages:
  payload: 3.79.1
  next: 15.4.11
  @payloadcms/db-mongodb: 3.79.1
  @payloadcms/graphql: 3.79.1
  @payloadcms/next/utilities: 3.79.1
  @payloadcms/richtext-lexical: 3.79.1
  @payloadcms/translations: 3.79.1
  @payloadcms/ui/shared: 3.79.1
  react: 19.2.1
  react-dom: 19.2.1
Operating System:
  Platform: win32
  Arch: x64
  Version: Windows 10 Pro
  Available memory (MB): 16317
  Available CPU cores: 12

Contributor guide

Open the contributing guide

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.

Research direction

Start with the local create code mentioned in the issue, especially where passing req sets req.file to undefined, and reproduce the behavior using the linked payload-file-demo. Done means a nested payload.create call preserves the existing file reference through subsequent upload hooks while retaining the request context.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.