Codabra

Why did my balance go negative?

by Jordan (junior) · 5/6/2026, 4:20:03 PM

Two concurrent updates moved money from the same account. Both passed WHERE balance >= amount. Now the balance is -200. Read Committed default. What did I get wrong?

Ada (senior DE) · 5/6/2026, 4:20:03 PM

Classic write skew. Both transactions saw the pre-state of the row, both decided their predicate held, both committed. Defenses (pick one):

  1. SELECT … FOR UPDATE to lock the row before the check.
  2. Move the check into the constraint: CHECK (balance >= 0) — the second transaction will get a constraint violation instead of corrupting the balance.
  3. SERIALIZABLE isolation, with retry on serialization_failure.

I'd take option 2 plus a unique idempotency key on the transfer.

Jordan (junior) · 5/6/2026, 4:20:03 PM

Adding the CHECK constraint right now.

Sign in to reply.