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
onInit seed (src/seed.ts) creates a product with two variant types and then attempts to create a variant, which triggers the validateOptions hook.
- The Variants collection is overridden in
src/payload.config.ts with trash: 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: deletedAt and 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
Describe the Bug
The
validateOptionshook on theoptionsfield of the Variants collection (added by@payloadcms/plugin-ecommerce) queries sibling variants using adeletedAtfilter:If a user disables trash on the Variants collection (e.g. via
variantsCollectionOverridesettingtrash: false), thedeletedAtfield no longer exists on that collection. Payload's join-query sanitizer then rejects the query with: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
deletedAtclause is redundant either way: whentrash: true, Payload already excludes soft-deleted documents by default unlesstrash: trueis explicitly passed to the query. So the fix is to drop the clause.Suggested Fix
Remove the
deletedAtclause from thewherepassed to thevariantsjoin invalidateOptions:Link to the code that reproduces this issue
https://github.com/jhb-dev/payload-ecommerce-variants-trash-validate
Reproduction Steps
pnpm install && pnpm dev).onInitseed (src/seed.ts) creates a product with two variant types and then attempts to create a variant, which triggers thevalidateOptionshook.src/payload.config.tswithtrash: false:QueryError: The following path cannot be queried: deletedAtand the operation aborts.Captured server log:
Which area(s) are affected?
plugin: ecommerce
Environment Info