nopSolutions/nopCommerce · error · NopException

Anonymous checkout disabled for recurring items

Error message

Anonymous checkout disabled for recurring items

What it means

Thrown in CreateOrderAsync when the cart contains recurring items, the customer is a guest (not logged in), and recurring billing is active. Vault-based recurring payments require a registered customer account to associate payment tokens; guest checkout cannot persist tokens for future billing cycles.

Source

Thrown at src/Plugins/Nop.Plugin.Payments.PayPalCommerce/Services/PayPalCommerceServiceManager.cs:1651

            if (string.IsNullOrEmpty(settings.MerchantId))
                throw new NopException("Merchant PayPal ID not set");

            var details = await PrepareCartDetailsAsync(placement);

            var savedPaymentToken = await _tokenService.GetByIdAsync(cardId ?? 0);
            if (savedPaymentToken is not null && savedPaymentToken.CustomerId != details.Customer.Id)
                throw new NopException("Card details not found");

            var isGuest = await _customerService.IsGuestAsync(details.Customer);
            var isRecurring = await _shoppingCartService.ShoppingCartIsRecurringAsync(details.Cart);
            if (isRecurring)
            {
                if (!settings.UseVault)
                    throw new NopException("Vault disabled");

                if (isGuest)
                    throw new NopException("Anonymous checkout disabled for recurring items");

                var (error, cycleLength, cyclePeriod, totalCycles) = await _shoppingCartService.GetRecurringCycleInfoAsync(details.Cart);
                if (!string.IsNullOrEmpty(error))
                    throw new NopException(error);
            }

            var paymentRequest = await _orderProcessingService.GetProcessPaymentRequestAsync();
            var (order, _) = await GetCreatedOrderAsync(settings, paymentRequest, placement, details.ShippingIsRequired, paymentSource);
            if (paymentRequest is null || order is null)
                paymentRequest = new();

            //prepare purchase unit
            var purchaseUnit = await PreparePurchaseUnitAsync(settings, details, paymentRequest.OrderGuid.ToString());

            //whether we should create a new order
            if (order is null || isRecurring)
            {
                var isCard = string.Equals(paymentSource, nameof(PaymentSource.Card), StringComparison.InvariantCultureIgnoreCase);

View on GitHub (pinned to 64bdf2ff08)

Solutions

  1. Require customers to log in or create an account before adding recurring products to the cart
  2. Add a UI guard on the product page for recurring items that requires authentication before 'Add to cart'
  3. Configure nopCommerce to disable guest checkout globally if the store sells recurring products
  4. Redirect guest customers with recurring items to the login/registration page before checkout
Defensive patterns

Strategy: validation

Validate before calling

// Check if guest customer has recurring items before checkout
var isRecurring = await _shoppingCartService.ShoppingCartIsRecurringAsync(cart);
var isGuest = await _customerService.IsGuestAsync(customer);
if (isRecurring && isGuest)
{
    return Redirect("/login?returnUrl=" + Url.Action("Checkout"));
}

Type guard

static bool CanGuestCheckout(bool isRecurring, bool isGuest)
    => !isRecurring || !isGuest;

Try / catch

var (order, error) = await manager.CreateOrderAsync(settings, placement, paymentSource, cardId, saveCard);
if (!string.IsNullOrEmpty(error) && error.Contains("Anonymous checkout disabled"))
    return RedirectToRoute("Login", new { returnUrl = "/checkout" });

Prevention

When it happens

Trigger: isRecurring is true and isGuest is true — ShoppingCartIsRecurringAsync returned true and CustomerService.IsGuestAsync returned true for the current customer.

Common situations: A guest customer added a subscription or recurring product to the cart; the store allows guest checkout but recurring products require an account; the customer is not logged in or their session expired and they became a guest.

Related errors


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