nopSolutions/nopCommerce · error · Exception

Selected shipping method can't be loaded

Error message

Selected shipping method can't be loaded

What it means

Thrown by OpcSaveShippingMethod at line 1859 when the parsed shipping option name/systemName cannot be matched in the available shipping options list (cache via generic attribute, or freshly loaded via GetShippingOptionsAsync). The selected method does not exist for this cart/address/provider, so the Find returns null. Hardcoded literal message. The submitted selection is no longer valid.

Source

Thrown at src/Presentation/Nop.Web/Controllers/CheckoutController.cs:1859

            //find it
            //performance optimization. try cache first
            var shippingOptions = await _genericAttributeService.GetAttributeAsync<List<ShippingOption>>(customer,
                NopCustomerDefaults.OfferedShippingOptionsAttribute, store.Id);
            if (shippingOptions == null || !shippingOptions.Any())
            {
                //not found? let's load them using shipping service
                shippingOptions = (await _shippingService.GetShippingOptionsAsync(cart, await _customerService.GetCustomerShippingAddressAsync(customer),
                    customer, shippingRateComputationMethodSystemName, store.Id)).ShippingOptions.ToList();
            }
            else
            {
                //loaded cached results. let's filter result by a chosen shipping rate computation method
                shippingOptions = shippingOptions.Where(so => so.ShippingRateComputationMethodSystemName.Equals(shippingRateComputationMethodSystemName, StringComparison.InvariantCultureIgnoreCase))
                    .ToList();
            }

            var shippingOption = shippingOptions.Find(so => !string.IsNullOrEmpty(so.Name) && so.Name.Equals(selectedName, StringComparison.InvariantCultureIgnoreCase))
                                 ?? throw new Exception("Selected shipping method can't be loaded");

            //parse DesiredDeliveryDate
            var desiredDeliveryDate = await ParseSelectedShippingMethodDeliveryDateAsync(shippingOption, shippingOptions, form);
            if (desiredDeliveryDate != null)
                await _genericAttributeService.SaveAttributeAsync(customer, NopCustomerDefaults.DesiredDeliveryDate, desiredDeliveryDate, store.Id);

            //save
            await _genericAttributeService.SaveAttributeAsync(customer, NopCustomerDefaults.SelectedShippingOptionAttribute, shippingOption, store.Id);

            //load next step
            return await OpcLoadStepAfterShippingMethod(cart);
        }
        catch (Exception exc)
        {
            await _logger.WarningAsync(exc.Message, exc, await _workContext.GetCurrentCustomerAsync());
            return Json(new { error = 1, message = exc.Message });
        }
    }

View on GitHub (pinned to 64bdf2ff08)

Solutions

  1. Force a recompute of shipping options for the current cart/address before selection.
  2. Ensure the selected shippingRateComputationMethodSystemName matches an active, registered provider.
  3. Invalidate the cached OfferedShippingOptionsAttribute when address/cart changes.
  4. Render the option list from the same GetShippingOptionsAsync source used server-side.

Example fix

// before: posting a cached option whose provider is gone
$.post('OpcSaveShippingMethod', { shippingoption: 'Ground___Shipping.NowRemoved' });
// after: recompute and only send an offered option
const options = await fetchShippingOptions(cart, address); // server-side source
const pick = options[0];
$.post('OpcSaveShippingMethod', { shippingoption: `${pick.Name}___${pick.ShippingRateComputationMethodSystemName}` });
Defensive patterns

Strategy: validation

Validate before calling

// Recompute offered options for the current cart/address and only send one of them.
var offered = await _genericAttributeService
    .GetAttributeAsync<List<ShippingOption>>(customer, NopCustomerDefaults.OfferedShippingOptionsAttribute, store.Id);
if (offered == null || !offered.Any())
    offered = (await _shippingService.GetShippingOptionsAsync(cart, shipAddress, customer, systemName, store.Id)).ShippingOptions.ToList();
var match = offered.Find(o => o.Name == selectedName);
if (match == null) { /* re-render options, abort submit */ }

Type guard

function isOfferedShippingOption(value /*: string*/, offered /*: {Name:string;ShippingRateComputationMethodSystemName:string}[]*/) {
  const [name, sys] = value.split('___');
  return offered.some(o => o.Name === name && o.ShippingRateComputationMethodSystemName === sys);
}

Try / catch

if (data.error && /shipping method can't be loaded/i.test(data.message)) {
  await invalidateOfferedShippingCache();
  await reloadShippingOptions();
}

Prevention

When it happens

Trigger: Client posts a valid 'Name___SystemName' but no matching ShippingOption exists: provider disabled, options not computed for the current address/cart, cache (OfferedShippingOptionsAttribute) stale, or the systemName doesn't match any active shipping rate computation method.

Common situations: Shipping provider disabled/removed after options were cached; address changed so options differ; cart contents changed so rates differ; provider plugin uninstalled; cached OfferedShippingOptions attribute from a previous address.

Related errors


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