Skip to content

Taxonomy

Check-then-act across an await

It was true when you checked, and something happened in between.

What it looks like

  • A read, an await, and then a write that assumes the read still holds.
  • 'Does it exist?' followed by 'create it', with a suspension point between them.
  • A balance or quota checked before an awaited call and spent after it.

Why it survives review

Single-threaded reasoning says nothing can happen between two adjacent lines — and in synchronous code that is true. An await breaks it: other work runs at that point. The window is small, so it never fires under test and always fires in production eventually.

How to see it

  1. Treat every await as a place where arbitrary other code runs. Ask what could change between the check and the act.
  2. Look for the pattern read-decide-write spanning a suspension point, and ask whether the decision is still valid.
  3. The fix is usually to make the operation atomic — a conditional update — rather than to shorten the window.

A minimal pair

Correct

const created = await store.createIfAbsent(key, value);
if (!created) return conflict();

Defective

if (await store.has(key)) return conflict();
await store.set(key, value);

Two requests that both pass the check before either writes, and the second silently overwrites the first.

Practise it

No exercise in the corpus sets this class yet. The lesson stands on its own — the corpus grows by adding subjects, and pretending otherwise would hide the gap.