nopSolutions/nopCommerce · warning · NopException

Checkout.MinOrderTotalAmount

Error message

Checkout.MinOrderTotalAmount

What it means

Thrown when the cart total is below the configured minimum order total threshold (_orderSettings.MinOrderTotalAmount) and ValidateMinOrderTotalAmountAsync returns false. The message uses the localized 'Checkout.MinOrderTotalAmount' resource formatted with the threshold in the customer's currency. Unlike the subtotal check, this is evaluated after all discounts, gift cards, and reward points are applied to the final total.

Source

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

            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)
    {
        if (details.Customer.BillingAddressId is null)
            throw new NopException("Billing address is not provided");

        var billingAddress = await _customerService.GetCustomerBillingAddressAsync(details.Customer);

        if (!CommonHelper.IsValidEmail(billingAddress?.Email))

View on GitHub (pinned to 64bdf2ff08)

Solutions

  1. Increase the cart value or reduce discount/gift card/reward point usage so the final total meets the threshold.
  2. Review _orderSettings.MinOrderTotalAmount in admin and lower or disable it if too restrictive.
  3. Show both minimum subtotal and minimum total requirements on the cart/checkout pages.
  4. Set MinOrderTotalAmount to 0 if no minimum order total is needed.

Example fix

// before: orderSettings.MinOrderTotalAmount = 25m; cart total after discounts = 18m
// after: orderSettings.MinOrderTotalAmount = 0m;  // disable minimum total
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

async Task<bool> MeetsMinTotalAsync(IOrderTotalCalculationService svc, IList<ShoppingCartItem> cart, decimal min)
{
    var (total, _, _, _, _, _) = await svc.GetShoppingCartTotalAsync(cart);
    return min <= 0 || (total.HasValue && total.Value >= min);
}

Try / catch

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

Prevention

When it happens

Trigger: The store has MinOrderTotalAmount set (e.g. $20) and the customer's cart total after all discounts and reward points falls below it. A large discount or reward point redemption brings the final total under the minimum. Gift card application reduces the effective payable total below the threshold.

Common situations: Customer redeems reward points or applies a gift card that reduces the total below the minimum. A percentage discount or category-wide sale drops the payable amount. Admin set both MinOrderSubtotalAmount and MinOrderTotalAmount with the total threshold higher than expected. A new minimum was set mid-session.

Related errors


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