nopSolutions/nopCommerce · error · NopException
Shopping cart has no recurring items
Error message
Shopping cart has no recurring items
What it means
Thrown by CreateSetupTokenAsync when the current shopping cart has no recurring items (ShoppingCartIsRecurringAsync returns false). Setup tokens are meaningful only for recurring/billing-agreement purchases, so a one-time cart is rejected before contacting PayPal. It is surfaced as the Error string.
Source
Thrown at src/Plugins/Nop.Plugin.Payments.PayPalCommerce/Services/PayPalCommerceServiceManager.cs:2621
/// <param name="settings">Plugin settings</param>
/// <returns>
/// A task that represents the asynchronous operation
/// The task result contains the setup token; error message if exists
/// </returns>
public async Task<(PaymentToken PaymentToken, string Error)> CreateSetupTokenAsync(PayPalCommerceSettings settings)
{
return await HandleFunctionAsync(async () =>
{
if (!IsConfigured(settings))
throw new NopException("Plugin not configured");
if (!settings.UseVault)
throw new NopException("Vault disabled");
var details = await PrepareCartDetailsAsync(ButtonPlacement.PaymentMethod);
if (!await _shoppingCartService.ShoppingCartIsRecurringAsync(details.Cart))
throw new NopException("Shopping cart has no recurring items");
if (await _customerService.IsGuestAsync(details.Customer))
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 orderGuid = Guid.NewGuid().ToString();
var items = await PrepareOrderItemsAsync(details);
var orderAmount = await PrepareOrderMoneyAsync(details, items);
var shipping = await PrepareShippingDetailsAsync(details, details.ShippingOption?.Name);
var context = PrepareRecurringPaymentContext(details);
var payer = await PrepareBillingDetailsAsync(settings, details);
//prepare subscription (billing plan) details
var billingCycle = new BillingCycleView on GitHub (pinned to 64bdf2ff08)
Solutions
- Only invoke CreateSetupTokenAsync when the cart actually contains recurring products.
- Pre-check await _shoppingCartService.ShoppingCartIsRecurringAsync(cart) before showing the recurring checkout button.
- Verify recurring products have valid recurring cycle settings so they are recognized as recurring.
Example fix
// before
var (token, err) = await _serviceManager.CreateSetupTokenAsync(settings);
// after
var details = await PrepareCartDetailsAsync(ButtonPlacement.PaymentMethod);
if (!await _shoppingCartService.ShoppingCartIsRecurringAsync(details.Cart))
{
NotifyError("This flow is only for recurring orders");
return;
}
var (token, err) = await _serviceManager.CreateSetupTokenAsync(settings); Defensive patterns
Strategy: validation
Validate before calling
if (!await _shoppingCartService.ShoppingCartIsRecurringAsync(cart))
return; Type guard
static async Task<bool> HasRecurring(IShoppingCartService svc, IList<ShoppingCartItem> cart) =>
await svc.ShoppingCartIsRecurringAsync(cart); Try / catch
var (token, error) = await mgr.CreateSetupTokenAsync(settings);
if (!string.IsNullOrEmpty(error))
NotifyError(error); Prevention
- Only route to the setup-token flow for carts with recurring items.
- Ensure recurring products have valid cycle settings.
When it happens
Trigger: The setup-token entry point is reached for a cart containing only standard (non-recurring) products; a recurring product was removed from the cart leaving only one-time items.
Common situations: Front-end routing calls the recurring setup-token flow for all checkouts regardless of cart type; a recurring product was misconfigured (no recurring cycle) so it no longer counts as recurring.
Related errors
- Setup token not set
- {error}
- Capture ID not set
- Payment token not created
- Product (Id={sci.ProductId}) cannot be loaded
AI-assisted analysis of nopSolutions/nopCommerce@64bdf2ff08 (2026-08-13).
Data as JSON: /api/errors/b72b7d3095bf7d29.
Report an issue: GitHub.