nopSolutions/nopCommerce · error · NopException

Product (Id={sci.ProductId}) cannot be loaded

Error message

Product (Id={sci.ProductId}) cannot be loaded

What it means

Thrown by ShoppingCartService while validating recurring shipment schedules when GetProductByIdAsync(sci.ProductId) returns null. The cart item references a product that cannot be loaded from the database. This is a referential-integrity break: the ShoppingCartItem exists but its Product is missing, so recurring-cycle validation cannot read product.IsRecurring / cycle fields and aborts.

Source

Thrown at src/Libraries/Nop.Services/Orders/ShoppingCartService.cs:1945

    /// <returns>
    /// A task that represents the asynchronous operation
    /// The task result contains the error (if exists); otherwise, empty string. Cycle length. Cycle period. Total cycles
    /// </returns>
    public virtual async Task<(string error, int cycleLength, RecurringProductCyclePeriod cyclePeriod, int totalCycles)> GetRecurringCycleInfoAsync(IList<ShoppingCartItem> shoppingCart)
    {
        var rezCycleLength = 0;
        RecurringProductCyclePeriod rezCyclePeriod = 0;
        var rezTotalCycles = 0;

        int? cycleLength = null;
        RecurringProductCyclePeriod? cyclePeriod = null;
        int? totalCycles = null;

        var conflictError = await _localizationService.GetResourceAsync("ShoppingCart.ConflictingShipmentSchedules");

        foreach (var sci in shoppingCart)
        {
            var product = await _productService.GetProductByIdAsync(sci.ProductId) ?? throw new NopException($"Product (Id={sci.ProductId}) cannot be loaded");

            if (!product.IsRecurring)
                continue;

            //cycle length
            if (cycleLength.HasValue && cycleLength.Value != product.RecurringCycleLength)
                return (conflictError, rezCycleLength, rezCyclePeriod, rezTotalCycles);
            cycleLength = product.RecurringCycleLength;

            //cycle period
            if (cyclePeriod.HasValue && cyclePeriod.Value != product.RecurringCyclePeriod)
                return (conflictError, rezCycleLength, rezCyclePeriod, rezTotalCycles);
            cyclePeriod = product.RecurringCyclePeriod;

            //total cycles
            if (totalCycles.HasValue && totalCycles.Value != product.RecurringTotalCycles)
                return (conflictError, rezCycleLength, rezCyclePeriod, rezTotalCycles);
            totalCycles = product.RecurringTotalCycles;

View on GitHub (pinned to 64bdf2ff08)

Solutions

  1. Run a data-integrity check for cart items whose ProductId has no matching product and clean them up.
  2. Before cart operations, ensure products referenced by active cart items are not hard-deleted; prefer soft-delete/Hide or remove cart items on product delete.
  3. Fix the test/import to insert the Product in the same transaction as the cart item.
  4. Catch NopException around the recurring validation call, log sci.Id/ProductId, and remove the offending cart item with a user-facing message.

Example fix

// before
var (warnings, _, _, _) = await _shoppingCartService.GetRecurringCycleInfoAsync(cart);

// after
foreach (var sci in cart)
{
    var p = await _productService.GetProductByIdAsync(sci.ProductId);
    if (p is null)
    {
        await _shoppingCartService.DeleteShoppingCartItemAsync(sci.Id, ensureOnlyActiveCheckoutAttributes: false);
        continue;
    }
}
var (warnings, _, _, _) = await _shoppingCartService.GetRecurringCycleInfoAsync(cart);
Defensive patterns

Strategy: validation

Validate before calling

foreach (var sci in cart)
{
    var p = await _productService.GetProductByIdAsync(sci.ProductId);
    if (p is null)
    {
        await _shoppingCartService.DeleteShoppingCartItemAsync(sci.Id, ensureOnlyActiveCheckoutAttributes: false);
        cart = cart.Where(x => x.Id != sci.Id).ToList();
    }
}

Try / catch

try { await _shoppingCartService.GetRecurringCycleInfoAsync(cart); }
catch (NopException ex) when (ex.Message.Contains("cannot be loaded"))
{
    // a cart item references a missing product; log and remove offending items
    _logger.LogError(ex, "Cart references a missing product");
}

Prevention

When it happens

Trigger: Adding to / validating a cart that contains a ShoppingCartItem whose ProductId points to a deleted, purged, or non-existent product, while the cart is being checked for recurring-schedule conflicts. Reachable during AddToCart, cart validation, and checkout when a recurring product is involved.

Common situations: A product was deleted (soft/hard) but cart items still reference it; a botched import/migration; a test that seeds a cart item without the product; caching a stale ProductId after the product was removed.

Related errors


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