nopSolutions/nopCommerce · warning · NopException

Checkout.MinOrderSubtotalAmount

Error message

Checkout.MinOrderSubtotalAmount

What it means

Thrown when the cart subtotal is below the configured minimum order subtotal threshold (_orderSettings.MinOrderSubtotalAmount) and ValidateMinOrderSubtotalAmountAsync returns false. The message uses the localized resource 'Checkout.MinOrderSubtotalAmount' formatted with the threshold converted to the customer's currency. This enforces a minimum spend policy at order placement.

Solutions

  1. Increase the cart subtotal by adding items or removing discount codes that push it below the threshold.
  2. Review and adjust _orderSettings.MinOrderSubtotalAmount in admin (Configuration > Settings > Order settings) if the threshold is too high.
  3. Display the minimum order requirement prominently on the cart page before the customer proceeds to checkout.
  4. Set MinOrderSubtotalAmount to 0 if no minimum is desired.

Example fix

// before (admin): orderSettings.MinOrderSubtotalAmount = 50m; cart subtotal = 35m
// after: orderSettings.MinOrderSubtotalAmount = 0m;  // disable minimum
// or: customer adds more items to exceed 50m
Defensive patterns

Strategy: validation

Validate before calling

// Before PlaceOrder, check minimum subtotal
if (await ValidateMinOrderSubtotalAmountAsync(cart) == false)
{
    var minAmount = await _currencyService.ConvertFromPrimaryStoreCurrencyAsync(
        _orderSettings.MinOrderSubtotalAmount, currentCurrency);
    var formatted = await _priceFormatter.FormatPriceAsync(minAmount, true, false);
    _notificationService.ErrorNotification(
        string.Format(await _localizationService.GetResourceAsync("Checkout.MinOrderSubtotalAmount"), formatted));
    return RedirectToRoute("ShoppingCart");
}

Type guard

async Task<bool> MeetsMinSubtotalAsync(IShoppingCartService svc, IList<ShoppingCartItem> cart, decimal min) =>
    min <= 0 || (await svc.GetShoppingCartSubTotalAsync(cart)).subTotal >= min;

Try / catch

try
{
    var result = await _orderProcessingService.PlaceOrderAsync(processPaymentRequest);
}
catch (NopException ex) when (ex.Message.Contains("MinOrderSubtotal"))
{
    _notificationService.ErrorNotification(ex.Message);
    return RedirectToRoute("ShoppingCart");
}

Prevention

When it happens

Trigger: The store has MinOrderSubtotalAmount configured (e.g. $50) and the customer's cart subtotal (after item-level discounts but before order-level discounts) falls below it. The setting was increased after the customer added items. The subtotal calculation is affected by tax inclusion settings reducing the visible subtotal.

Common situations: Admin set a minimum order value to cover shipping/handling costs. A customer applies a discount code that brings the subtotal below the minimum. Tax display settings make the subtotal appear higher than the pre-tax subtotal used for validation. A B2B store with a minimum order requirement.

Related errors


AI-assisted analysis of nopSolutions/nopCommerce@64bdf2ff08 (2026-08-13). Data as JSON: /api/errors/a3ca35aeb8f0ef8c. Report an issue: GitHub.

Appendix: source

Thrown at src/Libraries/Nop.Services/Orders/OrderProcessingService.cs:522

            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};"));
        }

        //min totals validation
        if (!await ValidateMinOrderSubtotalAmountAsync(details.Cart))
        {
            var minOrderSubtotalAmount = await _currencyService.ConvertFromPrimaryStoreCurrencyAsync(_orderSettings.MinOrderSubtotalAmount, currentCurrency);
            throw new NopException(string.Format(await _localizationService.GetResourceAsync("Checkout.MinOrderSubtotalAmount"),
                await _priceFormatter.FormatPriceAsync(minOrderSubtotalAmount, true, false)));
        }

        if (!await ValidateMinOrderTotalAmountAsync(details.Cart))
        {
            var minOrderTotalAmount = await _currencyService.ConvertFromPrimaryStoreCurrencyAsync(_orderSettings.MinOrderTotalAmount, currentCurrency);
            throw new NopException(string.Format(await _localizationService.GetResourceAsync("Checkout.MinOrderTotalAmount"),
                await _priceFormatter.FormatPriceAsync(minOrderTotalAmount, true, false)));
        }
    }

    /// <summary>
    /// Prepare and validate billing address
    /// </summary>
    /// <param name="details">PlaceOrder container</param>
    /// <returns>A task that represents the asynchronous operation</returns>
    /// <exception cref="NopException">Validation problems</exception>
    protected virtual async Task PrepareAndValidateBillingAddressAsync(PlaceOrderContainer details)

View on GitHub (pinned to 64bdf2ff08)