nopSolutions/nopCommerce · error · NopException

Setup token not set

Error message

Setup token not set

What it means

Thrown by CreateRecurringOrderAsync when the setupTokenId argument is null or empty. The recurring order is built from an approved setup token (the payer authenticated it), so the token id is required to create the payment token. This guard fires before cart preparation and is returned as the Error string.

Source

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

    /// <returns>
    /// A task that represents the asynchronous operation
    /// The task result contains the created order; error message if exists
    /// </returns>
    public async Task<(Order Order, string Error)> CreateRecurringOrderAsync(PayPalCommerceSettings settings, string setupTokenId)
    {
        return await HandleFunctionAsync(async () =>
        {
            if (!IsConfigured(settings))
                throw new NopException("Plugin not configured");

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

            if (!settings.UseVault)
                throw new NopException("Vault disabled");

            if (string.IsNullOrEmpty(setupTokenId))
                throw new NopException("Setup token not set");

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

            //try to create payment token by the approved setup token
            var payer = await PrepareBillingDetailsAsync(settings, details);
            var paymentTokenRequest = new CreatePaymentTokenRequest
            {
                Customer = payer,
                PaymentSource = new()
                {
                    Token = new()
                    {

View on GitHub (pinned to 64bdf2ff08)

Solutions

  1. Pass the setup token id returned/recorded from the setup-token approval step into CreateRecurringOrderAsync.
  2. Validate !string.IsNullOrEmpty(setupTokenId) before the call and re-prompt/abort if missing.
  3. Ensure the approval callback persists setupTokenId (e.g. in order generic attributes or session) before invoking order creation.

Example fix

// before
var (order, err) = await _serviceManager.CreateRecurringOrderAsync(settings, setupTokenId);

// after
if (string.IsNullOrEmpty(setupTokenId))
{
    NotifyError("Missing approved setup token; restart the recurring payment flow");
    return;
}
var (order, err) = await _serviceManager.CreateRecurringOrderAsync(settings, setupTokenId);
Defensive patterns

Strategy: validation

Validate before calling

if (string.IsNullOrEmpty(setupTokenId))
    return;

Type guard

static string SetupToken(string id) => string.IsNullOrEmpty(id) ? null : id;

Try / catch

var (order, error) = await mgr.CreateRecurringOrderAsync(settings, setupTokenId);
if (!string.IsNullOrEmpty(error))
    NotifyError(error);

Prevention

When it happens

Trigger: Calling CreateRecurringOrderAsync without the setup token id; the setup-token approval callback did not pass the token id forward; the token id was lost between the approval redirect and the order-creation step.

Common situations: Payer approved the setup token but the return URL/session did not carry setupTokenId; integration wired the wrong query/attribute name; approval webhook handled but id not persisted.

Related errors


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