nopSolutions/nopCommerce · error · NopException

Purchase was not initiated by customer

Error message

Purchase was not initiated by customer

What it means

Thrown by PreparePurchaseModelAsync when order.CustomerId does not equal the current customer's Id. Same ownership guard as the cart event: the purchase ConversionsEvent is only built when the order belongs to the customer active in the work context.

Source

Thrown at src/Plugins/Nop.Plugin.Widgets.FacebookPixel/Services/FacebookPixelService.cs:721

        };
    }

    /// <summary>
    /// Prepare purchase event model
    /// </summary>
    /// <param name="order">Order</param>
    /// <returns>
    /// A task that represents the asynchronous operation
    /// The task result contains the ConversionsEvent model
    /// </returns>
    protected async Task<ConversionsEvent> PreparePurchaseModelAsync(Order order)
    {
        ArgumentNullException.ThrowIfNull(order);

        //check whether the purchase was initiated by the customer
        var customer = await _workContext.GetCurrentCustomerAsync();
        if (order.CustomerId != customer.Id)
            throw new NopException("Purchase was not initiated by customer");

        //prepare event object
        var currency = await _currencyService.GetCurrencyByIdAsync(_currencySettings.PrimaryStoreCurrencyId);
        var contentsProperties = await (await _orderService.GetOrderItemsAsync(order.Id)).SelectAwait(async item =>
        {
            var product = await _productService.GetProductByIdAsync(item.ProductId);
            var sku = product != null ? await _productService.FormatSkuAsync(product, item.AttributesXml) : string.Empty;
            var quantity = product != null ? (int?)item.Quantity : null;
            return new { id = sku, quantity = quantity };
        }).Cast<object>().ToListAsync();
        var eventObject = new ConversionsEventCustomData
        {
            ContentType = "product",
            Contents = contentsProperties,
            Currency = currency?.CurrencyCode,
            Value = order.OrderTotal
        };

View on GitHub (pinned to 64bdf2ff08)

Solutions

  1. Impersonate (set the work context to) the order's customer before preparing the event, or bypass it.
  2. Skip the event (return null) instead of throwing for admin/backend order views.
  3. Run purchase-event preparation inline in the checkout flow where the customer context is guaranteed correct.

Example fix

// before
var customer = await _workContext.GetCurrentCustomerAsync();
if (order.CustomerId != customer.Id)
    throw new NopException("Purchase was not initiated by customer");

// after — only emit during the live checkout context
var customer = await _workContext.GetCurrentCustomerAsync();
if (order.CustomerId != customer.Id)
    return null; // not the purchaser's own session — skip silently
Defensive patterns

Strategy: validation

Validate before calling

var current = await _workContext.GetCurrentCustomerAsync();
if (order.CustomerId != current.Id) return null; // not the purchaser's session

Type guard

static bool IsOrderOwner(Order order, Customer current) => order.CustomerId == current.Id;

Try / catch

try { await PreparePurchaseModelAsync(order); }
catch (NopException ex) when (ex.Message.Contains("not initiated by customer"))
{ _logger.Debug(ex, "Skipping purchase event for non-owner order"); }

Prevention

When it happens

Trigger: An Order belonging to customer A is passed while the work context resolves customer B: admin order view, backend order-processing job, post-checkout context where the session customer changed.

Common situations: Admin viewing/reprocessing an order placed by a customer; a background integration job iterating orders without impersonating each order's customer; a webhook handler reconstructing the work context incorrectly.

Related errors


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