This error occurs when attempting to chain .then() on a value that is undefined instead of a Promise. It typically happens when a function fails to return a Promise, breaking the promise chain.
This error occurs when you try to call the `.then()` method on a value that is `undefined` instead of a Promise object. In JavaScript and Node.js, when you chain promises together, each handler in the chain is expected to either return a value or return another Promise. If a function that's supposed to return a Promise doesn't actually return anything, it implicitly returns `undefined`, and any subsequent attempt to call `.then()` on that `undefined` value will throw this TypeError. This is one of the most common mistakes when working with promise chains. The error message tells you exactly what went wrong: you're trying to access the 'then' property (which is a method on Promise objects) on something that doesn't have itβnamely, `undefined`. This breaks the promise chain and prevents your asynchronous code from executing as expected.
Examine your stack trace to find which .then() call is receiving undefined. Look for the line number in the error message.
// Example error stack:
// TypeError: Cannot read property 'then' of undefined
// at processData (app.js:15:8)Check the function being called just before this line. That's likely where the Promise is missing.
The most common fix is adding the return keyword before your Promise or asynchronous function call.
Before (broken):
function fetchData() {
fetch('https://api.example.com/data')
.then(response => response.json());
// Missing return - function implicitly returns undefined
}
// This will fail:
fetchData().then(data => console.log(data));After (fixed):
function fetchData() {
return fetch('https://api.example.com/data')
.then(response => response.json());
}
// Now works correctly:
fetchData().then(data => console.log(data));Each .then() handler in a chain must return a value or Promise if you want to continue the chain.
Before (broken):
somePromise()
.then(result => {
processResult(result);
// Missing return - returns undefined
})
.then(data => {
// data is undefined here!
console.log(data);
});After (fixed):
somePromise()
.then(result => {
return processResult(result);
})
.then(data => {
console.log(data); // Now data has the correct value
});If you're using async/await, make sure async functions return the expected value or Promise.
Before (broken):
async function getData() {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
// Missing return - function returns Promise<undefined>
}
getData().then(data => console.log(data)); // data is undefinedAfter (fixed):
async function getData() {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return data;
}
getData().then(data => console.log(data)); // Works correctlyWhen testing with Jest or other frameworks, ensure mocked async functions return Promises.
Before (broken):
// Mock doesn't return a Promise
jest.mock('./api', () => ({
fetchUser: jest.fn(() => { userId: 123 })
}));After (fixed):
jest.mock('./api', () => ({
fetchUser: jest.fn(() => Promise.resolve({ userId: 123 }))
}));Check that the function you're calling is documented to return a Promise. Some functions may look asynchronous but don't actually return Promises.
// Check function return type
function myFunction(): Promise<Data> { // TypeScript helps here
return fetchData();
}Use TypeScript or JSDoc to explicitly declare return types, which helps catch these errors during development.
Promise Chain Architecture:
When building complex promise chains, consider using async/await instead of .then() chains for better readability and easier debugging. Async/await makes it more obvious when you're missing a return statement because you use the await keyword explicitly.
TypeScript Benefits:
Using TypeScript with strict type checking will catch many of these errors at compile time. If a function is declared to return Promise<T> but doesn't actually return anything, TypeScript will flag it as an error.
Alternative: Promise.all() for Concurrent Operations:
If you're chaining promises sequentially but they could run in parallel, use Promise.all() instead:
// Sequential (slow):
return firstPromise()
.then(result1 => secondPromise())
.then(result2 => thirdPromise());
// Concurrent (fast):
return Promise.all([
firstPromise(),
secondPromise(),
thirdPromise()
]);Debugging Tips:
Add console.log statements to verify what your functions are returning:
function myFunction() {
const promise = fetch('/api/data');
console.log('Returning:', promise); // Should log Promise object, not undefined
return promise;
}Common Pattern: Implicit Returns with Arrow Functions:
Arrow functions with expression bodies implicitly return the result, which can help avoid this error:
// Explicit return (verbose):
.then(data => {
return processData(data);
})
// Implicit return (concise):
.then(data => processData(data))However, be careful with object literals, which need parentheses:
// Wrong - looks like a block, returns undefined:
.then(data => { value: data.value })
// Correct - returns an object:
.then(data => ({ value: data.value }))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