Negative Quantity Cart Bugs: Turning Line Items Into Credits
Checkout math is boring until a quantity field accepts -1. Then a line item stops being a purchase and starts acting like a credit. I've seen this survive fancy React carts because the browser UI clamps the spinner while the API still trusts whatever JSON you send.
Stop treating quantity as a UI concern. Treat it as money.
Find the real cart write path
Map every place that changes quantity: POST /cart, PATCH /cart/items/{id}, GraphQL updateCartItem, and any "save for later" or wishlist merge that rewrites the basket. Intercept the request and note which fields the client owns—quantity, qty, count, sometimes units.
Send quantity: -1 on a cheap SKU you control. If the UI rejects it, use Repeater anyway. A 200 with a negative line total is the first signal. Next, mix one positive item and one negative item. Does the order subtotal drop below the positive item alone? Can the negative line exceed the positive total and push the cart toward zero or a refund-shaped balance?
Watch server-side rounding. Some stacks store integers and silently coerce floats; others store signed decimals and happily credit you. Either way, capture the cart JSON before and after so triage can replay the math.
Boundary values beat random fuzzing
Try -1, 0, -999999, and a quantity larger than inventory. Zero often deletes the line or leaves a ghost row. Huge negatives may overflow into a positive total—that is a different bug and still reportable if money moves wrong.
Also test type confusion: "quantity": "-1" as a string, null, empty array, and duplicate line items for the same SKU with opposing signs. Bundle and subscription SKUs are worth a second pass because their pricing pipelines sometimes skip the same validators as simple products.
Do not complete a checkout against a live merchant account with a manipulated total unless the program explicitly allows purchase tests and you can cancel cleanly. Prefer sandboxes, demo stores, or stopping at the order preview / payment intent stage where the discounted amount is visible.
What a solid proof looks like
Own two products or one product plus a gift-wrap SKU. Set the expensive line to -1 and the cheap line to 1. Screenshot the cart API response showing line totals and the payable amount. If the store creates an order object before payment, export that ID and the computed amount_due.
Severity tracks cash impact and reach. A negative quantity that only breaks your own cart is low. One that lets you buy stock for free or generate store credit is high. Mention whether inventory decrements on negative lines—some warehouses get weird and that becomes an availability issue too.
Recommend server-side validation: quantity must be a positive integer within stock limits, recalculate totals only from SKU and server price tables, and reject signed values at the schema layer. Client clamps are cosmetic.
Business-logic cart bugs reward patience more than scanners. One reproducible negative line that changes amount_due is enough.