nopSolutions/nopCommerce · error · NopException
Cart is empty
Error message
Cart is empty
What it means
Thrown by PrepareAndValidateShoppingCartAndCheckoutAttributesAsync when the customer's shopping cart (loaded by type ShoppingCart and store) contains no items. An empty cart cannot produce an order, so this is the first sanity check in the PlaceOrder pipeline.
Source
Thrown at src/Libraries/Nop.Services/Orders/OrderProcessingService.cs:499
/// <summary>
/// Prepare and validate shopping cart and checkout attributes
/// </summary>
/// <param name="details">PlaceOrder container</param>
/// <param name="processPaymentRequest">payment info holder</param>
/// <param name="currentCurrency">The working currency</param>
/// <returns>A task that represents the asynchronous operation</returns>
/// <exception cref="NopException">Validation problems</exception>
protected virtual async Task PrepareAndValidateShoppingCartAndCheckoutAttributesAsync(PlaceOrderContainer details, ProcessPaymentRequest processPaymentRequest, Currency currentCurrency)
{
//checkout attributes
details.CheckoutAttributesXml = await _genericAttributeService.GetAttributeAsync<string>(details.Customer, NopCustomerDefaults.CheckoutAttributes, processPaymentRequest.StoreId);
details.CheckoutAttributeDescription = await _checkoutAttributeFormatter.FormatAttributesAsync(details.CheckoutAttributesXml, details.Customer);
//load shopping cart
details.Cart = await _shoppingCartService.GetShoppingCartAsync(details.Customer, ShoppingCartType.ShoppingCart, processPaymentRequest.StoreId);
if (!details.Cart.Any())
throw new NopException("Cart is empty");
//validate the entire shopping cart
var warnings = await _shoppingCartService.GetShoppingCartWarningsAsync(details.Cart, details.CheckoutAttributesXml, true);
if (warnings.Any())
throw new NopException(warnings.Aggregate(string.Empty, (current, next) => $"{current}{next};"));
//validate individual cart items
foreach (var sci in details.Cart)
{
var product = await _productService.GetProductByIdAsync(sci.ProductId);
var sciWarnings = await _shoppingCartService.GetShoppingCartItemWarningsAsync(details.Customer,
sci.ShoppingCartType, product, processPaymentRequest.StoreId, sci.AttributesXml,
sci.CustomerEnteredPrice, sci.RentalStartDateUtc, sci.RentalEndDateUtc, sci.Quantity, false, sci.Id);
if (sciWarnings.Any())
throw new NopException(sciWarnings.Aggregate(string.Empty, (current, next) => $"{current}{next};"));
}
View on GitHub (pinned to 64bdf2ff08)
Solutions
- Guard the payment submission with a client-side check that disables the button after first click and verifies cart count.
- In custom integrations, verify IShoppingCartService.GetShoppingCartAsync returns items before constructing the payment request.
- Ensure the StoreId on the ProcessPaymentRequest matches the store where cart items were added.
- Redirect users with an empty cart away from the payment page.
Example fix
// before: var result = await _orderProcessingService.PlaceOrderAsync(processPaymentRequest);
// after:
var cart = await _shoppingCartService.GetShoppingCartAsync(customer, ShoppingCartType.ShoppingCart, storeId);
if (!cart.Any())
return; // or redirect to cart page
var result = await _orderProcessingService.PlaceOrderAsync(processPaymentRequest); Defensive patterns
Strategy: validation
Validate before calling
// Before PlaceOrder, confirm the cart has items
var cart = await _shoppingCartService.GetShoppingCartAsync(
customer, ShoppingCartType.ShoppingCart, storeId);
if (!cart.Any())
{
_notificationService.ErrorNotification("Your cart is empty.");
return RedirectToRoute("ShoppingCart");
} Type guard
bool CartHasItems(IList<ShoppingCartItem> cart) => cart != null && cart.Count > 0;
Try / catch
try
{
var result = await _orderProcessingService.PlaceOrderAsync(processPaymentRequest);
}
catch (NopException ex) when (ex.Message == "Cart is empty")
{
return RedirectToRoute("ShoppingCart");
} Prevention
- Disable the payment submit button after first click (prevent double-submit that empties the cart).
- Redirect away from the payment page if the cart is empty.
- In custom integrations, always verify cart items exist before constructing a ProcessPaymentRequest.
- Ensure the StoreId on the payment request matches the store where cart items were added.
- Use optimistic concurrency or a lock to prevent duplicate PlaceOrder calls for the same cart.
When it happens
Trigger: PlaceOrder or ProcessPayment is invoked when the customer has no active shopping cart items for the current store. The cart was emptied (items purchased or removed) between the checkout review page and the payment submission. A programmatic payment request was created with a stale CustomerId or StoreId that doesn't match the cart.
Common situations: Double-click or double-submit of the payment button where the first request completes and empties the cart. Session timeout causing the cart reference to become stale. A custom integration building a ProcessPaymentRequest manually without ensuring cart items exist. Store-mismatch where the cart was created under one store and PlaceOrder runs under another.
Related errors
- Shipping address is not provided
- {warning1};{warning2};...
- Billing address is not provided
- recurringCyclesError
- Order total couldn't be calculated
AI-assisted analysis of nopSolutions/nopCommerce@64bdf2ff08 (2026-08-13).
Data as JSON: /api/errors/856cd67222d6c2cf.
Report an issue: GitHub.