nopSolutions/nopCommerce · warning · Exception
This shipment is already shipped
Error message
This shipment is already shipped
What it means
Thrown by ShipAsync when shipment.ShippedDateUtc already has a value. The shipment was already marked shipped, so re-shipping is idempotency-violating and refused. Uses plain Exception.
Source
Thrown at src/Libraries/Nop.Services/Orders/OrderProcessingService.cs:2244
}
/// <summary>
/// Send a shipment
/// </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 ShipAsync(Shipment shipment, bool notifyCustomer)
{
ArgumentNullException.ThrowIfNull(shipment);
var order = await _orderService.GetOrderByIdAsync(shipment.OrderId) ?? throw new Exception("Order cannot be loaded");
if (order.PickupInStore)
throw new Exception("This shipment is can't be shipped. The order has been placed with 'pickup in store' shipping option.");
if (shipment.ShippedDateUtc.HasValue)
throw new Exception("This shipment is already shipped");
shipment.ShippedDateUtc = DateTime.UtcNow;
await _shipmentService.UpdateShipmentAsync(shipment);
//process products with "Multiple warehouse" support enabled
await BookReservedInventoryAsync(shipment, string.Format(await _localizationService.GetResourceAsync("Admin.StockQuantityHistory.Messages.Ship"), shipment.OrderId));
//check whether we have more items to ship
if (await _orderService.HasItemsToAddToShipmentAsync(order) || await _orderService.HasItemsToShipAsync(order))
order.ShippingStatusId = (int)ShippingStatus.PartiallyShipped;
else
order.ShippingStatusId = (int)ShippingStatus.Shipped;
await _orderService.UpdateOrderAsync(order);
//add a note
await AddOrderNoteAsync(order, $"Shipment# {shipment.Id} has been sent");
if (notifyCustomer)
View on GitHub (pinned to 64bdf2ff08)
Solutions
- Guard the caller: check shipment.ShippedDateUtc.HasValue before calling ShipAsync and treat it as a no-op.
- Add idempotency at the API/controller layer so duplicate requests are deduplicated.
- Disable the Ship control in the UI once ShippedDateUtc is set.
Example fix
// before
await _orderProcessingService.ShipAsync(shipment, notify);
// after
if (shipment.ShippedDateUtc.HasValue)
return Ok("Already shipped.");
await _orderProcessingService.ShipAsync(shipment, notify); Defensive patterns
Strategy: validation
Validate before calling
if (shipment.ShippedDateUtc.HasValue)
return Ok($"Shipment {shipment.Id} already shipped on {shipment.ShippedDateUtc:o}.");
await _orderProcessingService.ShipAsync(shipment, notifyCustomer); Type guard
bool IsAlreadyShipped(Shipment shipment) => shipment.ShippedDateUtc.HasValue;
Try / catch
try
{
await _orderProcessingService.ShipAsync(shipment, notifyCustomer);
}
catch (Exception ex) when (ex.Message == "This shipment is already shipped")
{
// idempotent success - return the existing shipped state
return Ok("Shipment was already shipped.");
} Prevention
- Check shipment.ShippedDateUtc.HasValue before shipping and treat a set value as success.
- Add idempotency keys at the API layer so duplicate Ship requests are deduplicated.
- Disable the Ship control in the UI once ShippedDateUtc is set to prevent double-submits.
When it happens
Trigger: Double-click on the Ship button; a retried API call; scheduled job reprocessing the same shipment; webhook redelivery triggering Ship twice.
Common situations: UI double-submit; network retry with no idempotency key; concurrent admin operators; background job crash-and-retry.
Related errors
- This shipment is can't be shipped. The order has been placed
- This shipment is can't be marked as 'ready for pickup'. The
- Admin.Catalog.Products.Import.CategoriesWithSameNameNotSuppo
- Order cannot be loaded
- This shipment is already marked as 'ready for pickup'
AI-assisted analysis of nopSolutions/nopCommerce@64bdf2ff08 (2026-08-13).
Data as JSON: /api/errors/58fa846d7fe39a93.
Report an issue: GitHub.