payloadcms / payloadcms/payload
[plugin-ecommerce] validateOptions hook fails when trash is disabled on Variants collection
@paulpopus is already working on this.
Since Apr 24, 2026.
- Dominant language
- TypeScript
- Stars
- 44.8k
- Forks
- 4.2k
- Avg merge
- 2d 21h
- Merged PRs (30d)
- 53
Description
Describe the Bug
The validateOptions hook on the options field of the Variants collection (added by @payloadcms/plugin-ecommerce) queries sibling variants using a deletedAt filter:
// packages/plugin-ecommerce/src/collections/variants/createVariantsCollection/hooks/validateOptions.ts
const product = await req.payload.findByID({
id: productID,
collection: productsCollectionSlug,
depth: 1,
joins: {
variants: {
where: {
deletedAt: { exists: false },
...(data.id && { id: { not_equals: data.id } }),
},
},
},
// ...
})
If a user disables trash on the Variants collection (e.g. via variantsCollectionOverride setting trash: false), the deletedAt field no longer exists on that collection. Payload's join-query sanitizer then rejects the query with:
QueryError: The following path cannot be queried: deletedAt
The variant create/update fails with a toast error in the admin UI, and the operation fails in the REST/Local APIs with status 400.
The deletedAt clause is redundant either way: when trash: true, Payload already excludes soft-deleted documents by default unless trash: true is explicitly passed to the query. So the fix is to drop the clause.
Suggested Fix
Remove the deletedAt clause from the where passed to the variants join in validateOptions:
joins: {
variants: {
where: {
...(data.id && { id: { not_equals: data.id } }),
},
},
},
Link to the code that reproduces this issue
https://github.com/jhb-dev/payload-ecommerce-variants-trash-validate
Reproduction Steps
- Clone the reproduction repository and run the development server (
pnpm install && pnpm dev). - The
onInitseed (src/seed.ts) creates a product with two variant types and then attempts to create a variant, which triggers thevalidateOptionshook. - The Variants collection is overridden in
src/payload.config.tswithtrash: false:products: { variants: { variantsCollectionOverride: ({ defaultCollection }) => ({ ...defaultCollection, trash: false, }), }, }, - Expected: the variant is created successfully.
- Actual: the create operation throws
QueryError: The following path cannot be queried: deletedAtand the operation aborts.
Captured server log:
INFO: Seeding product + variant types/options...
INFO: Attempting to create a variant (this triggers the bug)...
ERROR: Variant creation failed (reproduced bug)
err: {
"type": "QueryError",
"message": "The following path cannot be queried: deletedAt",
"stack":
QueryError: The following path cannot be queried: deletedAt
at validateQueryPaths (.../payload/dist/database/queryValidation/validateQueryPaths.js:69:19)
at sanitizeJoinQuery (.../payload/dist/database/sanitizeJoinQuery.js:90:5)
at findByIDOperation (.../payload/dist/collections/operations/findByID.js:65:32)
at validateOptions (.../@payloadcms/plugin-ecommerce/dist/collections/variants/createVariantsCollection/hooks/validateOptions.js:17:25)
...
"data": [ { "path": "deletedAt" } ],
}
Which area(s) are affected?
plugin: ecommerce
Environment Info
Binaries:
Node: 24.3.0
npm: 11.4.2
pnpm: 10.33.0
Relevant Packages:
payload: 3.84.0
@payloadcms/plugin-ecommerce: 3.84.0
next: 15.4.11
@payloadcms/db-mongodb: 3.84.0
@payloadcms/graphql: 3.84.0
@payloadcms/next/utilities: 3.84.0
@payloadcms/richtext-lexical: 3.84.0
@payloadcms/translations: 3.84.0
@payloadcms/ui/shared: 3.84.0
react: 19.2.1
react-dom: 19.2.1
Operating System:
Platform: darwin
Arch: arm64
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.