Description
When a cart line references a product that has been deleted or unpublished from the Hydrogen sales channel, the Storefront API returns null for the non-nullable field ProductVariant.product. That fails the entire CartQuery, not just the affected line.
In Hydrogen's `storefront.query`:
Cannot return null for non-nullable field ProductVariant.product
To debug the query `CartQuery`, try it in GraphiQL.
To investigate the issue, examine this stack trace:
at loader (app/routes/api/cart.ts:21)
Two consequences:
cart.get() throws in the loader, so /api/cart returns a 500. The cart bootstrap fails on every page, leaving the cart drawer stuck on its loading spinner site-wide — not only on the cart page.
- The cart cannot recover on its own.
CART_MUTATION_FRAGMENT selects product as well, so add/remove/update mutations fail the same way. The cart id stays permanently unusable until the shopper is issued a new one.
Affected call sites of cart.get():
app/routes/api/cart.ts
app/routes/cart/cart-page.tsx
app/routes/cart/checkout.tsx
Query fragments selecting merchandise { ... on ProductVariant { product { ... } } }: app/graphql/fragments.ts (CART_QUERY_FRAGMENT and CART_MUTATION_FRAGMENT).
Steps to reproduce
- Add a product to the cart.
- Delete the product, or unpublish it from the Hydrogen sales channel.
- Reload any page on the storefront.
Notes
A defensive wrapper around cart.get() (catch, log, return null) was prototyped and reverted — it contains the crash but does not restore the poisoned cart. Recovering the cart needs a separate decision, since resetting the cart id on any query failure would also discard valid carts on transient API errors.
Description
When a cart line references a product that has been deleted or unpublished from the Hydrogen sales channel, the Storefront API returns
nullfor the non-nullable fieldProductVariant.product. That fails the entireCartQuery, not just the affected line.Two consequences:
cart.get()throws in the loader, so/api/cartreturns a 500. The cart bootstrap fails on every page, leaving the cart drawer stuck on its loading spinner site-wide — not only on the cart page.CART_MUTATION_FRAGMENTselectsproductas well, so add/remove/update mutations fail the same way. The cart id stays permanently unusable until the shopper is issued a new one.Affected call sites of
cart.get():app/routes/api/cart.tsapp/routes/cart/cart-page.tsxapp/routes/cart/checkout.tsxQuery fragments selecting
merchandise { ... on ProductVariant { product { ... } } }:app/graphql/fragments.ts(CART_QUERY_FRAGMENTandCART_MUTATION_FRAGMENT).Steps to reproduce
Notes
A defensive wrapper around
cart.get()(catch, log, returnnull) was prototyped and reverted — it contains the crash but does not restore the poisoned cart. Recovering the cart needs a separate decision, since resetting the cart id on any query failure would also discard valid carts on transient API errors.