This error occurs when the await keyword is used outside of an async function context. JavaScript requires await to be inside async functions, async generators, or ES module top-level code to properly handle asynchronous operations.
This syntax error indicates that you're trying to use the `await` keyword in a location where JavaScript doesn't allow it. The `await` operator can only be used in specific contexts: inside async functions, async generator functions, or at the top level of ES modules. The reason for this restriction is fundamental to how JavaScript handles asynchronous code. When you use `await`, it pauses the execution of the surrounding async context while waiting for a Promise to resolve, but it never blocks the entire JavaScript runtime. Other tasks can continue running. This behavior is only possible within an async context that the JavaScript engine knows how to pause and resume. In Node.js, this error commonly appears when developers forget to mark a function as async, use await in regular callback functions, or try to use await in CommonJS modules without proper setup.
The most common fix is to add the async keyword before the function that contains the await statement.
Before (incorrect):
function fetchData() {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return data;
}After (correct):
async function fetchData() {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return data;
}This also applies to arrow functions, methods, and function expressions:
// Arrow function
const getData = async () => {
const result = await fetchData();
return result;
};
// Class method
class DataService {
async loadData() {
const data = await this.fetch();
return data;
}
}A common mistake is using await inside callbacks for array methods like forEach, map, or filter without making the callback function async.
Before (incorrect):
async function processItems(items) {
items.forEach(item => {
const result = await processItem(item); // Error!
console.log(result);
});
}After (correct option 1 - use for...of):
async function processItems(items) {
for (const item of items) {
const result = await processItem(item);
console.log(result);
}
}After (correct option 2 - async callback with Promise.all):
async function processItems(items) {
await Promise.all(
items.map(async (item) => {
const result = await processItem(item);
console.log(result);
})
);
}Note: forEach doesn't work well with async/await even if you make the callback async, because it doesn't wait for promises. Use for...of for sequential processing or Promise.all with map for parallel processing.
If you need to use await at the top level of your file (outside any function), you must use ES modules instead of CommonJS.
Option 1: Add to package.json
{
"type": "module"
}Then in your .js files:
// This now works at the top level
const data = await fetch('https://api.example.com/data');
console.log(await data.json());Option 2: Use .mjs extension
Rename your file from .js to .mjs:
mv script.js script.mjsFiles with .mjs extension are always treated as ES modules.
Requirements:
- Node.js 14.8.0+ (requires --harmony-top-level-await flag for 14.8-16.11)
- Node.js 16.12.0+ (works by default in ES modules)
Note: When using ES modules, you must use import instead of require:
// CommonJS (old)
const fs = require('fs');
// ES module (new)
import fs from 'fs';If you can't enable ES modules but need to use await at the top level, wrap your code in an async Immediately Invoked Function Expression (IIFE).
Pattern:
(async () => {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);
})();With error handling:
(async () => {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);
} catch (error) {
console.error('Error:', error);
}
})();This creates an async function and immediately invokes it, allowing you to use await inside without modifying the module system. This works in both CommonJS and ES modules.
If you cannot make the function async (for example, in certain callback scenarios), you can use traditional Promise chains with .then() and .catch().
Using async/await (not always possible):
const result = await someAsyncFunction();
console.log(result);Using Promise chains (works anywhere):
someAsyncFunction()
.then(result => {
console.log(result);
})
.catch(error => {
console.error(error);
});This approach is useful when:
- You're working with older callback-based APIs
- You're in a context that cannot be made async
- You need to maintain compatibility with older Node.js versions
Top-Level Await Considerations:
Top-level await in ES modules causes the entire module to behave like an async function. Other modules importing it will wait for any top-level awaits to resolve before executing their own code. This can affect application startup time and module initialization order. Use it judiciously for critical initialization tasks.
Constructor Limitations:
Class constructors cannot be async, and therefore cannot use await. If you need to perform async initialization in a class, use a factory pattern:
class DataService {
constructor(data) {
this.data = data;
}
static async create() {
const data = await fetchInitialData();
return new DataService(data);
}
}
// Usage
const service = await DataService.create();Performance with Array Methods:
When using async callbacks with array methods, understand the difference:
- for...of with await: Sequential execution (slower, but ordered)
- Promise.all with map: Parallel execution (faster, but unordered)
- forEach with async callbacks: Fires all at once but doesn't wait (often not desired)
CommonJS vs ES Modules:
Node.js uses CommonJS by default, which doesn't support top-level await. To check your module type:
# Check package.json
grep '"type"' package.json
# If not found, you're using CommonJS by defaultTranspilers and Build Tools:
If using TypeScript, Babel, or other build tools, ensure your target configuration supports async/await:
- TypeScript: Set "target": "ES2017" or higher in tsconfig.json
- Babel: Include @babel/plugin-transform-async-to-generator
Error: Listener already called (once event already fired)
EventEmitter listener already called with once()
Error: EACCES: permission denied, open '/root/file.txt'
EACCES: permission denied
Error: Invalid encoding specified (stream encoding not supported)
How to fix Invalid encoding error in Node.js readable streams
Error: EINVAL: invalid argument, open
EINVAL: invalid argument, open
TypeError: readableLength must be a positive integer (stream config)
TypeError: readableLength must be a positive integer in Node.js streams