Inventory reservation logic. Read stock, check positive, decrement. Read-modify-write. Under any concurrent load this oversells — two requests can both pass the check before either writes. Mesrai caught it the morning before a Black Friday code freeze.
The vulnerable diff
// checkout/reserve.ts
async function reserveItem(id: string) {
// BUG: classic TOCTOU — gap between read and write
const item = await db.items.findUnique({ where: { id } });
if (!item || item.stock <= 0) throw new Error("out of stock");
await db.items.update({
where: { id },
data: { stock: item.stock - 1 },
});
}What is wrong
TOCTOU (time-of-check to time-of-use) is the canonical concurrency bug: condition checked, then acted on, with no atomic guarantee between the two. Under load, multiple workers read the same stock value, all pass the check, all write the decrement. Two requests both see stock=1, both write stock=0 — two customers charged for one item. The fix is to make the check-and-write a single atomic database operation: `UPDATE items SET stock = stock - 1 WHERE id = ? AND stock > 0`. The database guarantees one and only one row update.
The attack
Load test reproduces the bug in seconds:
# 50 concurrent reservation attempts on a single-stock item
seq 1 50 | xargs -P 50 -I{} curl -s -X POST \
https://api.example.com/checkout/reserve \
-d '{"itemId":"sku-123"}'
# Result: stock = -49. Forty-nine angry customers.Production replays the same race naturally — checkout traffic concentrates on popular SKUs, dozens of parallel workers, no atomic guard.
Mesrai's review comment
mesraipilot · Bot · reviewed 90 sec ago
[mesrai] [code-review] [Logic] [TOCTOU] [critical]
This reserve flow has a TOCTOU race. Concurrent requests both pass
the `stock > 0` check before either writes the decrement, so stock
can go negative under load.
Fix: collapse the check and decrement into a single conditional
update — the database guarantees atomicity per row:
const { count } = await db.items.updateMany({
where: { id, stock: { gt: 0 } },
data: { stock: { decrement: 1 } },
});
if (count === 0) throw new Error("out of stock");
For multi-row reservations (cart), use a transaction with
SELECT ... FOR UPDATE or use a queue (one consumer per SKU).The fix
// checkout/reserve.ts — fixed
async function reserveItem(id: string) {
const { count } = await db.items.updateMany({
where: { id, stock: { gt: 0 } },
data: { stock: { decrement: 1 } },
});
if (count === 0) throw new Error("out of stock");
}The `WHERE stock > 0` predicate makes the check part of the UPDATE statement itself. The database row lock during UPDATE serializes concurrent attempts — only the first to acquire the lock and pass the predicate succeeds. Zero `count` means another request already drained the stock. No oversell possible.
Why human review missed it
Read-modify-write in the application looks correct because the read and write each look correct in isolation. The bug lives in the gap — invisible without a concurrency mental model. Mesrai catches the pattern by flagging every `findUnique` → conditional → `update` sequence on the same primary key, where the field being conditioned on is also being written.
Related rules + further reading
Mesrai rule pack: logic/no-toctou-on-counter — flags read-then-write on the same row field without atomic update.
Postgres docs: Concurrency Control — Explicit Locking.
Classic distributed systems reading: Bernstein, Hadzilacos, Goodman — Concurrency Control and Recovery.
Takeaway
Read-modify-write on inventory is oversell waiting for a Black Friday. Conditional UPDATE makes the check atomic. One line.