validateCart sends `index` for items in `itemsToAdd`, causing error 500 in request
Describe the bug
The validateCart resolver incorrectly sends the index field for new items being added to the cart (itemsToAdd). VTEX Checkout interprets the presence of index as a reference to an existing item and tries to update or replace it, causing incorrect mutations on the orderForm. This results in a 500 error and the item not being added to the cart.
This happens because:
- Items in
itemsToAddoriginate from the browser cart - These items do not exist in the orderForm yet
- The
Indexed<IStoreOffer>type allowsindexto leak into these new items - The
offerToOrderItemInputfunction forwards any existingindexwithout verification
As a result, VTEX may treat new items as updates to existing ones, breaking the optimistic cart reconciliation and causing the API to return a 500 error, preventing items from being successfully added to the cart.
Expected behavior
New items (itemsToAdd) must never include the index field in the payload sent to VTEX.
VTEX Checkout rules:
- Add item: no
index - Update item: must include
index
Therefore, any index found in items inside itemsToAdd should be removed before calling offerToOrderItemInput. Items should be successfully added to the cart without errors.
Current behavior
When browser cart objects contain an existing index (e.g., reused objects, old state, bundle logic), this value is propagated and sent to VTEX as if it were an update operation. This causes VTEX Checkout to return a 500 error, and the item fails to be added to the cart.
The problem occurs in:
- Creation of
itemsToAdd:
if (!maybeOriginItem) {
items.forEach((item) => acc.itemsToAdd.push(item))
return acc
}
- Conversion to orderForm input:
const changes = [...itemsToAdd, ...itemsToUpdate, ...itemsToDelete]
.map(offerToOrderItemInput)
offerToOrderItemInputfunction:
const offerToOrderItemInput = (offer: Indexed<IStoreOffer>): OrderFormInputItem => ({
quantity: offer.quantity,
seller: offer.seller.identifier,
id: offer.itemOffered.sku,
index: offer.index, // ❌ should not be sent when adding new items
attachments: ...
})
Steps to reproduce
- Add an item to the cart that contains an
IStoreOfferobject with theindexfield populated (e.g., from a previous validation or reused state) - Execute the
validateCartmutation with this cart - Observe that VTEX treats the new item as an update to an existing item
- Check that the API returns a 500 error
- Verify that the item is not added to the cart
- In more complex cases, an infinite
validateCartloop may occur because the orderForm never matches the browser cart
Possible Solution
Sanitize items inserted into itemsToAdd to ensure index is removed.
Option A (recommended): sanitize itemsToAdd before mapping
const sanitizedItemsToAdd = itemsToAdd.map(item => ({
...item,
index: undefined, // or: delete item.index
}))
Then:
const changes = [
...sanitizedItemsToAdd,
...itemsToUpdate,
...itemsToDelete,
].map(offerToOrderItemInput)
Option B: sanitize inside offerToOrderItemInput
const offerToOrderItemInput = (
offer: Indexed<IStoreOffer>
): OrderFormInputItem => ({
quantity: offer.quantity,
seller: offer.seller.identifier,
id: offer.itemOffered.sku,
index: offer.index ?? undefined, // ensures new items never send a meaningful index
attachments: ...
})
Option A is safer because it guarantees that itemsToAdd is always clean.
Additional context
Impact:
- 500 error when trying to add items to the cart
- Items not being added to the cart
- Wrong items being overridden inside the orderForm
- Incorrect quantity updates
- Parent/child bundle structure being corrupted
- Checkout interpreting an "add" as an "update"
- Infinite
validateCartloops because orderForm never matches the browser cart
This leads to unstable behavior and makes cart reconciliation unreliable.
When the problem is more apparent:
- UI reuses offer objects between renders
- Browser cart was built using previously validated data that already contained indexes
- Complex bundles (parent/child) are involved
Ensuring itemsToAdd is free of index is necessary to keep the cart consistent with VTEX Checkout's rules and prevent 500 errors.
Related files:
packages/api/src/platforms/vtex/resolvers/validateCart.ts(lines 68-81, 400-448)