Inventory Oversell Race Conditions: Buying More Than Stock Allows
"Only 1 left" is a promise. Concurrent checkouts test whether the warehouse ledger agrees.
If two buyers can both complete purchase for the last unit, the shop oversold. On limited drops, concert seats, or invite codes backed by a counter, that is real money and real support pain.
Pick a countable resource
Ideal targets:
- Product with stock displayed as 1–3
- Coupon marked "100 uses remaining"
- Booking slot with capacity 1
- Gift-card mint endpoint with a daily cap
Create the scarcity yourself when the program allows: as a merchant test user, set quantity to 1. Otherwise use a slow-moving SKU and still limit your blast radius.
Read the stock field from both the product page and a cart preview after hold. Some UIs lie with cached "in stock" badges while the API already returned available: 0. Trust the API numbers in your report.
The hold-then-buy pattern
Many carts "reserve" on add-to-cart and decrement on pay. Others decrement only at payment capture. Map which call changes stockRemaining.
Then:
- Session A and session B both add the last item (or both reach payment with qty 1).
- Fire both
complete/capturerequests together. - Inspect order IDs and the product stock endpoint.
Two successful paid orders against initial stock 1 is the clean proof. One success and one graceful out_of_stock means the lock worked.
Try quantity tampering in the same window: cart shows 1, you send quantity=5 on checkout if the field is writable. Races plus parameter trust stack nicely.
Reservations that expire add another window. Hold with A, wait until just before TTL, then complete with A and B together. Expiry jobs that increment stock without checking open checkouts recreate the last unit at the wrong moment.
Multi-warehouse catalogs can oversell one location while another still shows stock. If the API accepts a warehouseId or omits it, pin both checkouts to the same low-qty warehouse in your proof.
Timing and false confidence
A single lucky double-buy on a high-traffic item might be a known oversell tolerance. Ask whether the business accepts soft oversell and cancels later. Your report should show deterministic reproduction under test stock, not one flaky screenshot from a flash sale.
Also check async paths. If stock decrements in a queue worker, two API accepts can enqueue two fulfillments before the worker serializes. Read order status a minute later, not only the immediate 201.
Negative stock in the admin API is a gift to your severity section. Screenshot it.
Keep it ethical
Do not clear out a storefront's real inventory. Use test catalogs, staging, or merchant-configured qty. Refund or cancel your own orders after proof if the UI allows.
Recommend transactional inventory: decrement with a conditional update (WHERE stock >= :qty), unique constraints on reservation rows, and payment capture only after a successful hold. Idempotency keys stop duplicate clicks from the same buyer; they do not stop two buyers unless stock is locked.
Oversell races feel "obvious" after you find them. The writeup still needs stock before/after, both order IDs, and the exact parallel request set.