Looking for a structured path? Browse all JavaScript lessons.

Maintained by
Learning Platform content team
Reviewed by
Learning Platform source and executable-example contract

JavaScript async/await errors: four reliable fixes

Async bugs often look unrelated: [object Promise], Promise { <pending> }, an unhandled rejection, or an array of promises instead of values. They share one cause: code lost track of when a promise settles.

1. Await the value before using it

async function loadName() {
  return "Ada";
}

async function main() {
  const name = await loadName();
  console.log(`Hello, ${name}`);
}

main();

Expected output: Hello, Ada. Without await, name is a Promise, not a string.

2. Catch at the boundary that can recover

async function readConfig() {
  throw new Error("config unavailable");
}

async function main() {
  try {
    await readConfig();
  } catch (error) {
    console.log("Using defaults");
  }
}

main();

Expected output: Using defaults. A try block without await does not catch a later rejection if the promise escapes it.

3. Use Promise.all for independent work

const wait = (value) => Promise.resolve(value * 2);

async function main() {
  const values = await Promise.all([wait(2), wait(3)]);
  console.log(values); // [4, 6]
}

main();

Sequential await is correct when each operation depends on the previous result. For independent operations it adds avoidable latency.

4. Do not expect map(async …) to unwrap itself

items.map(async item => ...) returns Promise[]. Wrap it in await Promise.all(...). Conversely, forEach(async ...) does not wait at all; use for...of for deliberate serial work.

Failure mode

Adding .catch(() => {}) removes the warning and the evidence. Handle the error with a fallback, rethrow it with context, or let a top-level boundary report it.

Run these snippets in the JavaScript playground, then continue with Async and Promises and Error Handling.

Official references