{"record":{"id":"0eb776189861fc2b","repo":"dotnet/eShop","slug":"invalid-number-of-units","errorCode":null,"errorMessage":"Invalid number of units","messagePattern":"Invalid number of units","errorType":"exception","errorClass":"OrderingDomainException","httpStatus":null,"severity":"error","filePath":"src/Ordering.Domain/AggregatesModel/OrderAggregate/OrderItem.cs","lineNumber":27,"sourceCode":"    public string ProductName { get; private set; }\n    \n    public string PictureUrl { get; private set;}\n    \n    public decimal UnitPrice { get; private set;}\n    \n    public decimal Discount { get; private set; }\n    \n    public int Units { get; private set; }\n\n    public int ProductId { get; private set; }\n\n    protected OrderItem() { }\n\n    public OrderItem(int productId, string productName, decimal unitPrice, decimal discount, string pictureUrl, int units = 1)\n    {\n        if (units <= 0)\n        {\n            throw new OrderingDomainException(\"Invalid number of units\");\n        }\n\n        if ((unitPrice * units) < discount)\n        {\n            throw new OrderingDomainException(\"The total of order item is lower than applied discount\");\n        }\n\n        ProductId = productId;\n\n        ProductName = productName;\n        UnitPrice = unitPrice;\n        Discount = discount;\n        Units = units;\n        PictureUrl = pictureUrl;\n    }\n    \n    public void SetNewDiscount(decimal discount)\n    {","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/dotnet/eShop/blob/9b4f9434f46fdc5c1a6e9e936af2868340cdbc48/src/Ordering.Domain/AggregatesModel/OrderAggregate/OrderItem.cs#L9-L45","documentation":"Thrown by the OrderItem constructor when units is less than or equal to zero. An OrderItem represents a positive quantity of a product on an order, so a non-positive unit count is an invalid invariant; the constructor enforces it as a precondition. It is an OrderingDomainException.","triggerScenarios":"Constructing an OrderItem (directly or via Order.AddOrderItem, which news up an OrderItem for a new product line) with units <= 0. Typically the units value flowed from an order DTO/basket item whose Quantity was 0, negative, or an unset default.","commonSituations":"Basket item with Quantity 0 reaching the checkout handler; DTO-to-domain mapping that loses the Quantity field; a UI allowing zero-quantity lines; arithmetic that produced a negative units value (e.g. applying a delta).","solutions":["Validate at the application boundary that every order line has Quantity > 0 before mapping to OrderItem/ calling AddOrderItem.","Filter out zero-or-negative quantity lines when converting a basket to an order.","Use FluentValidation: RuleFor(x => x.Units).GreaterThan(0) on the create-order command.","Trace the Quantity source to the basket/client payload and ensure it is always a positive integer."],"exampleFix":"// before\norder.AddOrderItem(p.Id, p.Name, p.Price, 0, p.PictureUrl, line.Quantity);\n\n// after\nif (line.Quantity <= 0) throw new ArgumentException(\"Quantity must be positive\");\norder.AddOrderItem(p.Id, p.Name, p.Price, 0, p.PictureUrl, line.Quantity);","handlingStrategy":"validation","validationCode":"if (units <= 0) throw new ArgumentOutOfRangeException(nameof(units));\norder.AddOrderItem(productId, name, price, discount, url, units);","typeGuard":"static bool IsValidUnits(int units) => units > 0;","tryCatchPattern":"try {\n    order.AddOrderItem(id, name, price, discount, url, units);\n} catch (OrderingDomainException ex) when (ex.Message == \"Invalid number of units\") {\n    // reject the order line as 400 / drop it from the batch\n}","preventionTips":["Validate each order line Quantity > 0 before checkout.","Drop zero/negative quantity lines when converting basket to order.","Add FluentValidation GreaterThan(0) rules on create-order commands."],"tags":["domain","ordering","validation","precondition","ddd"],"backgroundTag":null,"analyzedSha":"9b4f9434f46fdc5c1a6e9e936af2868340cdbc48","analyzedAt":"2026-08-13T19:29:36.594Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}