Multiple products are not added to cart, when one product has a error

Topic summary

A developer encountered an issue where adding multiple products to a Shopify cart via JavaScript fails entirely if any single product has an error (out of stock, draft status, or invalid variant). The original implementation didn’t handle individual product failures gracefully.

Solutions provided:

  • Individual error handling: Process each product separately using promises or async/await, wrapping each add-to-cart call in try/catch blocks
  • Continue on failure: Allow successful products to be added even when others fail, logging errors for problematic items
  • Rate limiting consideration: Add delays (e.g., 300ms) between requests to avoid hitting Shopify’s ~2 requests/second API limit

Code approach:

  • Loop through products sequentially using for...of instead of forEach
  • Use fetch('/cart/add.js') for each product individually
  • Implement await with small delays between requests
  • Track successful additions and failed items separately

The discussion remains open as the original poster is evaluating the proposed solutions.

Summarized with AI on October 29. AI used: claude-sonnet-4-5-20250929.

I have a javascript code that adds multiple products to my cart add once.
Based on this documentation: Add products to cart

This normally works if non of the products has a issue like:

  • Not in stock.
  • Draft product.
  • Variant can not be found.

This are the basic response that i could get when doing this.
However it looks like all the other products are also not added to the cart when their is a issue.

Does anyone has a idee how to make these calls so that the products are added to cart except for the once that triggers those errors?

2 Likes

Hello @Michel2025

To ensure that all products are added to the cart except the ones that trigger errors like “out of stock,” “draft product,” or “variant not found,” you can modify your JavaScript code to handle each product individually. Instead of stopping the entire process when one product fails, you can process each product separately and catch the errors for each one. Here’s a general approach you can follow:

Approach:

  1. Loop through the products: For each product, you try to add it to the cart.

  2. Error handling: If the product has an error (like being out of stock or a draft product), catch the error and skip adding that product to the cart.

  3. Continue with other products: Continue processing the remaining products, even if one fails.

Example JavaScript Code:

function addProductsToCart(products) {
    let errors = []; // To store products that fail
    let successfulAdds = 0; // To track the successful additions

    // Loop through each product and try adding it to the cart
    products.forEach(product => {
        addProductToCart(product)
            .then(response => {
                successfulAdds++;
                console.log(`Product ${product.id} added successfully.`);
            })
            .catch(error => {
                errors.push({ product: product, error: error });
                console.log(`Error adding product ${product.id}: ${error.message}`);
            });
    });

    // After all products are processed, log the results
    setTimeout(() => {
        console.log(`${successfulAdds} products added to the cart.`);
        if (errors.length > 0) {
            console.log('Failed to add the following products:');
            errors.forEach(err => console.log(`Product ${err.product.id} failed due to: ${err.error.message}`));
        }
    }, 1000); // Adjust time if needed based on your network latency or number of products
}

function addProductToCart(product) {
    return new Promise((resolve, reject) => {
        // Your logic to add the product to the cart
        // This example assumes you're using Shopify's AJAX API to add the product
        let formData = {
            items: [
                {
                    id: product.variantId,
                    quantity: product.quantity
                }
            ]
        };

        fetch('/cart/add.js', {
            method: 'POST',
            body: JSON.stringify(formData),
            headers: { 'Content-Type': 'application/json' }
        })
            .then(response => response.json())
            .then(data => {
                if (data.status && data.status === 404) {
                    reject(new Error('Variant not found'));
                } else if (data.status && data.status === 422) {
                    reject(new Error('Out of stock'));
                } else if (data.status && data.status === 500) {
                    reject(new Error('Product is a draft'));
                } else {
                    resolve(data);
                }
            })
            .catch(err => reject(err));
    });
}

Explanation:
. addProductsToCart(products): This function processes the list of products and attempts to add each one to the cart. If there’s an error, it catches the error and logs it.

. addProductToCart(product): This function attempts to add a single product to the cart using Shopify’s /cart/add.js API. It returns a promise that resolves if the product is added successfully or rejects with an error message if it fails (e.g., variant not found, out of stock, or product is a draft).

. The loop ensures that all products are processed, and even if one fails, the rest will still be added.

Error Handling:
. The catch block inside the forEach ensures that the script continues executing even if a product fails to add to the cart.

. reject(new Error(‘Variant not found’)) and other similar errors are triggered when certain conditions (like the product being out of stock or not found) occur.

This approach should allow products to be added to the cart independently, even if some fail due to issues like those you mentioned.

Thank you :blush:

Hi,

Hope this will help

  • You need to add each product one by one, and if one fails, keep going.

JavaScript version example

const productsToAdd = [
  { id: 123456789, quantity: 1 },
  { id: 987654321, quantity: 2 },
  { id: 112233445, quantity: 1 }
];

async function addProductToCart(product) {
  try {
    const response = await fetch('/cart/add.js', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        items: [product]
      })
    });

    const data = await response.json();
    console.log(`Added product ${product.id} to cart.`);
  } catch (error) {
    console.warn(`Could not add product ${product.id}:`, error.message);
  }
}

async function addAllProducts(products) {
  for (const product of products) {
    await addProductToCart(product);
  }

  console.log('Done trying to add all products!');
}

addAllProducts(productsToAdd);

Thank you, i will look if your solution could help me.
The setTimeout is for the rate limit(to many request) i guess

1 Like

You’re welcome!
Just to clarify — in my example, the setTimeout wasn’t for rate limiting — it was simply used to wait a bit before summarizing/logging how many products were added or failed (because the fetch calls are asynchronous).
But you’re right to think about rate limits — Shopify does have limits (especially ~2 requests per second for storefront APIs like /cart/add.js).

If you are adding many products (like more than 2–3 at once), and you want to properly handle rate limits, you should actually queue the requests with a delay between them instead of blasting them all at once with forEach.

Here’s a better version using a small delay between each request:

async function addProductsToCart(products) {
    let errors = [];
    let successfulAdds = 0;

    for (const product of products) {
        try {
            await addProductToCart(product);
            successfulAdds++;
            console.log(`Product ${product.id} added successfully.`);
        } catch (error) {
            errors.push({ product: product, error: error });
            console.log(`Error adding product ${product.id}: ${error.message}`);
        }

        // Wait 300ms between requests to be safe
        await new Promise(resolve => setTimeout(resolve, 300));
    }

    console.log(`${successfulAdds} products added to the cart.`);
    if (errors.length > 0) {
        console.log('Failed to add the following products:');
        errors.forEach(err => console.log(`Product ${err.product.id} failed due to: ${err.error.message}`));
    }
}

Now each product will be added one by one, with a small 300ms pause between them to avoid hitting Shopify’s rate limits.

In short:
. setTimeout in the first example = just waiting before logging the summary.

. Proper rate limiting = add a delay (await new Promise(resolve => setTimeout(resolve, 300))) after each product like in this new code.

. Shopify cart APIs aren’t super strict, but it’s still a good idea to throttle your requests when adding multiple items at once.

Thank you :blush: