nopSolutions/nopCommerce · error · Exception
This shipment is already delivered
Error message
This shipment is already delivered
What it means
Thrown by OrderProcessingService.DeliverAsync when shipment.DeliveryDateUtc already has a value. It is an idempotency guard preventing a shipment from being delivered twice, which would otherwise overwrite the delivery timestamp, re-run the 'order fully delivered' shipping-status logic, and re-fire notifications.
Source
Thrown at src/Libraries/Nop.Services/Orders/OrderProcessingService.cs:2329
/// Marks a shipment as delivered
/// </summary>
/// <param name="shipment">Shipment</param>
/// <param name="notifyCustomer">True to notify customer</param>
/// <returns>A task that represents the asynchronous operation</returns>
public virtual async Task DeliverAsync(Shipment shipment, bool notifyCustomer)
{
ArgumentNullException.ThrowIfNull(shipment);
var order = await _orderService.GetOrderByIdAsync(shipment.OrderId) ?? throw new Exception("Order cannot be loaded");
if (!order.PickupInStore && !shipment.ShippedDateUtc.HasValue)
throw new Exception("This shipment is not shipped yet");
if (order.PickupInStore && !shipment.ReadyForPickupDateUtc.HasValue)
throw new Exception("This shipment is not yet ready for pickup");
if (shipment.DeliveryDateUtc.HasValue)
throw new Exception("This shipment is already delivered");
shipment.DeliveryDateUtc = DateTime.UtcNow;
await _shipmentService.UpdateShipmentAsync(shipment);
if (!await _orderService.HasItemsToAddToShipmentAsync(order) &&
!await _orderService.HasItemsToShipAsync(order) &&
!await _orderService.HasItemsToReadyForPickupAsync(order) &&
!await _orderService.HasItemsToDeliverAsync(order))
{
order.ShippingStatusId = (int)ShippingStatus.Delivered;
await _orderService.UpdateOrderAsync(order);
}
//add a note
await AddOrderNoteAsync(order, $"Shipment# {shipment.Id} has been delivered");
if (order.PickupInStore)
{
View on GitHub (pinned to 64bdf2ff08)
Solutions
- Guard before calling: if (shipment.DeliveryDateUtc.HasValue) return;
- Make the calling endpoint idempotent by keying off shipment.Id so duplicate deliver events collapse.
- Disable the 'Deliver' UI action once shipment.DeliveryDateUtc is set.
- For integrations, re-fetch the shipment right before delivery to narrow the check-then-act race.
Example fix
// before
await _orderProcessingService.DeliverAsync(shipment, true);
// after
if (shipment.DeliveryDateUtc.HasValue)
return; // already delivered
await _orderProcessingService.DeliverAsync(shipment, true); Defensive patterns
Strategy: validation
Validate before calling
if (shipment.DeliveryDateUtc.HasValue)
return; // already delivered
await _orderProcessingService.DeliverAsync(shipment, true); Try / catch
try { await _orderProcessingService.DeliverAsync(shipment, true); }
catch (NopException ex) when (ex.Message == "This shipment is already delivered")
{
// idempotent: treat as success
} Prevention
- Disable the 'Deliver' UI action once shipment.DeliveryDateUtc is set.
- Make the delivery endpoint idempotent, keyed on shipment.Id.
- Re-fetch the shipment immediately before delivery to reduce the race.
When it happens
Trigger: Calling DeliverAsync on a Shipment whose DeliveryDateUtc is non-null: duplicate admin 'Deliver' clicks, re-fired carrier webhooks, or concurrent requests on the same shipment.
Common situations: Store staff double-clicking Deliver; an ERP sync that reprocesses delivered shipments; a webhook retry storm after a transient HTTP failure; missing idempotency keys on a custom fulfillment endpoint.
Related errors
- This shipment is already marked as 'ready for pickup'
- This shipment is already shipped
- This shipment is not shipped yet
- This shipment is not yet ready for pickup
- Cannot do cancel for order.
AI-assisted analysis of nopSolutions/nopCommerce@64bdf2ff08 (2026-08-13).
Data as JSON: /api/errors/e043e0c61508477c.
Report an issue: GitHub.