# JavaScript: “SyntaxError: await is only valid in async functions and the top level bodies of modules”

> SyntaxError: await is only valid in async functions and the top level bodies of modules. Mark the function async, fix forEach callbacks, or use ES modules.

Canonical: https://app369.com/fix/await-is-only-valid-in-async-functions/
Last updated: 2026-11-08

Code fails to load with SyntaxError: await is only valid in async functions and the top level bodies of modules (Chrome, Node.js) or await is only valid in async functions, async generators and modules (Firefox). The await keyword sits in a function not marked async, often a callback, or at the top level of a file that runs as a script rather than a module.

**Short answer**

Find the function that directly contains the await and add async to it. If the await is inside a callback such as forEach or map, that callback is the function that needs async, and forEach will not wait for it, so use a for...of loop or Promise.all instead. For await at the top level, run the file as an ES module: type="module" on the script tag in browsers, or .mjs or "type": "module" in package.json for Node.js.

## **Where the await is, and the fix**

1. 01 ### **A function that is not marked async**
  > “Therefore, await cannot be used in sync tasks, such as functions, generator functions, or top level of scripts.” [**MDN, SyntaxError: await is only valid in async functions**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Bad_await) await is only allowed directly inside an async function. Add async to the function that contains it, then await that function where it is called.```
// wrong
function loadUser(id) {
  const res = await fetch(\`/api/users/${id}\`);
}

// right
async function loadUser(id) {
  const res = await fetch(\`/api/users/${id}\`);
  return res.json();
}
```
2. 02 ### **Inside a forEach, map or event callback** The outer function may be async, but the arrow function passed to forEach is a separate function. Marking that callback async removes the error, but forEach still does not wait. Use for...of to run in order, or Promise.all with map to run in parallel.```
for (const id of ids) {
  await save(id);
}

// or in parallel
await Promise.all(ids.map((id) => save(id)));
```
3. 03 ### **At the top level of a script**
  > “await at the top level of a module.” [**Node.js, Packages: syntax detection**](https://nodejs.org/api/packages.html) Top-level await works only in ES modules. In the browser, a classic script tag is not a module. In Node.js, .cjs files and packages with "type": "commonjs" are CommonJS. Node.js 22.7 and 20.19 and newer treat a .js file with no "type" field in the nearest package.json as a module when it uses top-level await, so the error mostly appears in older versions and in explicit CommonJS. If that file also calls require(), these versions throw a different error instead (Cannot determine intended module format): switch to import, or wrap the await in an async function.```
<script type="module" src="/main.js"></script>

// package.json
{ "type": "module" }
```
4. 04 ### **When the file has to stay CommonJS** Wrap the top-level code in an async function and call it, handling errors so a rejection does not go unnoticed.```
async function main() {
  const config = await loadConfig();
  startServer(config);
}
main().catch((err) => {
  console.error(err);
  process.exit(1);
});
```

Checked against the vendor’s docs on November 8, 2026: [MDN: SyntaxError: await is only valid in async functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Bad_await); [Node.js: Packages (syntax detection)](https://nodejs.org/api/packages.html).

## **Rather hand it over?**

Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.

- [from $450**App Fix Ticket**One reproducible bug in an existing mobile or web app, diagnosed and fixed.**See scope and start**](https://app369.com/fixed-price/flutter-firebase-bug-fix/)
- [from $450**AI-Built App Rescue**A Lovable, Bolt or Cursor app checked end to end in 3 days, then its worst problems fixed at a fixed price.****No issues worth fixing, no charge.**** If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.**See scope and start**](https://app369.com/fixed-price/ai-app-rescue/)

Related: [**Node.js “Cannot use import statement outside a module”**](https://app369.com/fix/node-cannot-use-import-statement-outside-module/) · [**“Uncaught (in promise)”**](https://app369.com/fix/uncaught-in-promise/) · [**Node.js ERR_REQUIRE_ESM**](https://app369.com/fix/node-err-require-esm/)

Questions

## **More on this error**

<details>

<summary>**Why does Safari say Unexpected identifier instead? **+</summary>

Safari reports the same mistake differently: outside an async function it does not treat await as a keyword, so it fails on the token after it. The fix is the same.

</details>

<details>

<summary>**Can I use await in a React useEffect? **+</summary>

Not directly in the effect function, because it must not return a promise. Define an async function inside the effect and call it.

</details>

<details>

<summary>**Can you fix it for me? **+</summary>

If one bug is the whole problem, the App Fix Ticket covers it: a written diagnosis first, then the fix. If the app has more going on, the Launch Check is a written check of the whole app. Each issue found is rated critical, high, medium or low, with where it is and how it was confirmed. No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.

</details>

A different error?

## **Describe it and get a written quote**

Send the error and what you were doing. You get a written scope, a fixed price and a timeline; Simon replies by email, usually within one business day.

[**Describe your problem **→](https://app369.com/contact/) [**All fixes**](https://app369.com/fix/)