Async bugs and race conditions in JavaScript
A missing await, results in the wrong order, and updates that overwrite each other under load.
What are async bugs and race conditions?
Code that assumes work has finished when it has not. The symptom is a Promise where a value should be, results arriving in an unexpected order, or state that is correct with one user and wrong with several.
Why it happens
An async function always returns a promise, so forgetting a single await hands the promise itself onward. `return somePromise` inside a try block escapes before it can reject, so the catch never runs. And every await is a point where other code can run — if you read a value, await, then write it back, anything that ran in the gap is silently overwritten.
How to recognise it
- "[object Promise]" or typeof 'object' where a value was expected.
- It works with one item and breaks with several.
- Output order changes between runs.
- A try/catch around async work never catches anything.
Error guides caused by this pattern
All error guides →In-depth guides for common exceptions and runtime errors triggered by async and race conditions, with working fixes and real-world examples:
How to fix it
Await everything that returns a promise, and use Promise.all when you need every result rather than the first. Never hold a copy of shared state across an await — read and write without yielding in between. Test concurrency with concurrent input; a sequential test cannot find a race.
Breaks vs Works Example
Breaks
// JavaScript: forEach does not await async functions
items.forEach(async (item) => {
await processItem(item);
});
console.log('Done'); // Logs before items finish!Works
// JavaScript: Promise.all waits for all concurrent operations
await Promise.all(items.map((item) => processItem(item)));
console.log('Done'); // Runs only after all items complete💡 Standard array callbacks (forEach, map, filter) do not wait for returned promises. Use Promise.all or for...of.
Practise async and race conditions
Working code with one bug in it. Find it, fix it in the browser, and see the explanation. No account needed.
Stuck on your own code?
Paste it into the visualizer and watch it run line by line, with every variable at every step. Free, and it runs in your browser.