{"record":{"id":"58fa846d7fe39a93","repo":"nopSolutions/nopCommerce","slug":"this-shipment-is-already-shipped","errorCode":null,"errorMessage":"This shipment is already shipped","messagePattern":"This shipment is already shipped","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"warning","filePath":"src/Libraries/Nop.Services/Orders/OrderProcessingService.cs","lineNumber":2244,"sourceCode":"    }\r\n\r\n    /// <summary>\r\n    /// Send a shipment\r\n    /// </summary>\r\n    /// <param name=\"shipment\">Shipment</param>\r\n    /// <param name=\"notifyCustomer\">True to notify customer</param>\r\n    /// <returns>A task that represents the asynchronous operation</returns>\r\n    public virtual async Task ShipAsync(Shipment shipment, bool notifyCustomer)\r\n    {\r\n        ArgumentNullException.ThrowIfNull(shipment);\r\n\r\n        var order = await _orderService.GetOrderByIdAsync(shipment.OrderId) ?? throw new Exception(\"Order cannot be loaded\");\r\n\r\n        if (order.PickupInStore)\r\n            throw new Exception(\"This shipment is can't be shipped. The order has been placed with 'pickup in store' shipping option.\");\r\n\r\n        if (shipment.ShippedDateUtc.HasValue)\r\n            throw new Exception(\"This shipment is already shipped\");\r\n\r\n        shipment.ShippedDateUtc = DateTime.UtcNow;\r\n        await _shipmentService.UpdateShipmentAsync(shipment);\r\n\r\n        //process products with \"Multiple warehouse\" support enabled\r\n        await BookReservedInventoryAsync(shipment, string.Format(await _localizationService.GetResourceAsync(\"Admin.StockQuantityHistory.Messages.Ship\"), shipment.OrderId));\r\n\r\n        //check whether we have more items to ship\r\n        if (await _orderService.HasItemsToAddToShipmentAsync(order) || await _orderService.HasItemsToShipAsync(order))\r\n            order.ShippingStatusId = (int)ShippingStatus.PartiallyShipped;\r\n        else\r\n            order.ShippingStatusId = (int)ShippingStatus.Shipped;\r\n        await _orderService.UpdateOrderAsync(order);\r\n\r\n        //add a note\r\n        await AddOrderNoteAsync(order, $\"Shipment# {shipment.Id} has been sent\");\r\n\r\n        if (notifyCustomer)\r","sourceCodeStart":2226,"sourceCodeEnd":2262,"githubUrl":"https://github.com/nopSolutions/nopCommerce/blob/64bdf2ff08c8b39e65717bcf974fb43dc2ef68f2/src/Libraries/Nop.Services/Orders/OrderProcessingService.cs#L2226-L2262","documentation":"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.","triggerScenarios":"Double-click on the Ship button; a retried API call; scheduled job reprocessing the same shipment; webhook redelivery triggering Ship twice.","commonSituations":"UI double-submit; network retry with no idempotency key; concurrent admin operators; background job crash-and-retry.","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."],"exampleFix":"// before\nawait _orderProcessingService.ShipAsync(shipment, notify);\n\n// after\nif (shipment.ShippedDateUtc.HasValue)\n    return Ok(\"Already shipped.\");\nawait _orderProcessingService.ShipAsync(shipment, notify);","handlingStrategy":"validation","validationCode":"if (shipment.ShippedDateUtc.HasValue)\n    return Ok($\"Shipment {shipment.Id} already shipped on {shipment.ShippedDateUtc:o}.\");\n\nawait _orderProcessingService.ShipAsync(shipment, notifyCustomer);","typeGuard":"bool IsAlreadyShipped(Shipment shipment) => shipment.ShippedDateUtc.HasValue;","tryCatchPattern":"try\n{\n    await _orderProcessingService.ShipAsync(shipment, notifyCustomer);\n}\ncatch (Exception ex) when (ex.Message == \"This shipment is already shipped\")\n{\n    // idempotent success - return the existing shipped state\n    return Ok(\"Shipment was already shipped.\");\n}","preventionTips":["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."],"tags":["shipment","idempotency","duplicate","fulfilment","nopcommerce"],"backgroundTag":null,"analyzedSha":"64bdf2ff08c8b39e65717bcf974fb43dc2ef68f2","analyzedAt":"2026-08-13T21:19:38.062Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}