faststore icon indicating copy to clipboard operation
faststore copied to clipboard

validateCart sends `index` for items in `itemsToAdd`, causing error 500 in request

Open andre-souza-dev opened this issue 1 month ago • 0 comments

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 itemsToAdd originate from the browser cart
  • These items do not exist in the orderForm yet
  • The Indexed<IStoreOffer> type allows index to leak into these new items
  • The offerToOrderItemInput function forwards any existing index without 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:

  1. Creation of itemsToAdd:
if (!maybeOriginItem) {
  items.forEach((item) => acc.itemsToAdd.push(item))
  return acc
}
  1. Conversion to orderForm input:
const changes = [...itemsToAdd, ...itemsToUpdate, ...itemsToDelete]
  .map(offerToOrderItemInput)
  1. offerToOrderItemInput function:
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

  1. Add an item to the cart that contains an IStoreOffer object with the index field populated (e.g., from a previous validation or reused state)
  2. Execute the validateCart mutation with this cart
  3. Observe that VTEX treats the new item as an update to an existing item
  4. Check that the API returns a 500 error
  5. Verify that the item is not added to the cart
  6. In more complex cases, an infinite validateCart loop 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 validateCart loops 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)

andre-souza-dev avatar Dec 09 '25 13:12 andre-souza-dev