Skip to content

fix: preserve req.file across nested Local API calls from hooks - #17712

Open
vjymisal0 wants to merge 1 commit into
payloadcms:mainfrom
vjymisal0:fix/15975-req-file-preservation
Open

fix: preserve req.file across nested Local API calls from hooks#17712
vjymisal0 wants to merge 1 commit into
payloadcms:mainfrom
vjymisal0:fix/15975-req-file-preservation

Conversation

@vjymisal0

Copy link
Copy Markdown

What?

req.file was being dropped when a hook called the Local API (e.g. payload.create/payload.update) and passed the original req through, per the documented pattern for preserving request context in nested hook calls.

Why?

createLocalReq mutates and returns the same req object passed via options.req — it does not clone it. In both createLocal (packages/payload/src/collections/operations/local/create.ts) and updateLocal (packages/payload/src/collections/operations/local/update.ts), the code unconditionally ran:

req.file = file ?? (await getFileByPath(filePath!))

When neither file nor filePath is passed to the nested Local API call (the normal case when a hook just forwards req), getFileByPath(undefined) resolves to undefined, overwriting whatever req.file was already set to by the in-flight upload operation. Any later hook (or a storage adapter like @payloadcms/storage-azure) that reads req.file off the same req then silently sees undefined.

How?

Only assign req.file when a file or filePath was explicitly provided to the Local API operation:

if (file || filePath) {
  req.file = file ?? (await getFileByPath(filePath!))
}

This preserves an existing req.file reference when the nested call isn't itself an upload, while leaving upload behavior for file/filePath options unchanged.

Added a regression test in test/uploads/int.spec.ts (req.file preservation across nested Local API calls) that sets req.file, calls payload.create on a non-upload collection with that req passed through (mirroring the hook pattern from the issue), and asserts req.file is still defined and unchanged afterward.

Test status

I was unable to run the integration test suite in my current sandbox due to environment constraints (insufficient local disk space to complete pnpm install for the full monorepo, and a Node version mismatch against the >=24.15.0 requirement in CLAUDE.md). I traced the fix and test logic through the code manually and am confident in the change, but flagging this explicitly rather than claiming a green run I couldn't produce. Happy to iterate on CI feedback.

Fixes #15975

createLocal and updateLocal mutate the req object passed via options.req
in place (createLocalReq returns the same reference), then unconditionally
overwrite req.file with `file ?? (await getFileByPath(filePath))`. When
neither `file` nor `filePath` is passed to the nested Local API call (the
documented pattern of forwarding the original req from a hook), this
resolves to undefined and clobbers a file reference already set on req by
the in-flight upload operation.

Only assign req.file when a file or filePath is explicitly provided to the
operation, so an existing req.file is preserved for hooks and adapters
further down the chain.

Fixes payloadcms#15975
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.

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

1 participant