How to spot check-then-act races (TOCTOU) in code review
A check-then-act race reads a value, decides, and then writes, with nothing stopping another request from changing the value in between. Two people get the last copy of a book, two signups claim the same username. Every test passes, because tests send one request at a time.
What it looks like in a diff
Two steps against shared state with application code between them: a read of a count or a status, an if, then a write. The check and the write are separate statements, not one atomic operation, and an await or a network call between them widens the gap.
Ask what happens when two requests run the same lines at the same time. If both can pass the check before either writes, the rule is not enforced. The fixes live in the database: a conditional update that checks the rule in its WHERE clause, a unique constraint, or a row lock held from the read to the write. A transaction alone does not help at the usual isolation levels (PostgreSQL's default READ COMMITTED, for one): both transactions can still read the old value.
Questions to ask in review
- What rule does this code enforce (a limit, uniqueness, a one-time use)?
- Is that rule checked and applied in one atomic step, or in two?
- What does the database guarantee here: a constraint, a lock, a conditional update?
- What does the user see when the second request loses the race?
How to word the comment
Name the input, the path it takes and what goes wrong, then the fix. For example (on an imagined PR, not one from the library):
Two requests can both see one copy available and both create a hold, so the library lends a book it does not have. Make it one step: a conditional update that decrements
availableonlyWHERE available > 0, and treat zero updated rows as no copy left.
Practise on real PRs
As of October 2026, the DiffDojo library has 5 live PRs that plant check-then-act races, across 4 stacks. They are not listed here: a PR you open knowing its bug teaches less. Each review is graded on whether you find the bug and explain it.