Fix: TypeError: Cannot read properties of undefined (reading 'xxx')
Part of: React & Frontend Errors
Quick Answer
How to fix 'TypeError: Cannot read properties of undefined', 'Cannot read property of undefined', and 'Cannot read properties of null' in JavaScript, TypeScript, and React. Covers optional chaining, async data fetching, destructuring, and nested object access.
The Error
You run your JavaScript code and hit one of these errors:
Modern browsers (Chrome 92+, Edge, Node 16.6+):
TypeError: Cannot read properties of undefined (reading 'name')Older browsers and Node versions:
TypeError: Cannot read property 'name' of undefinedThe null variant:
TypeError: Cannot read properties of null (reading 'name')All three mean the same thing: you tried to access a property on a value that is undefined or null. The 'name' part (or whatever property appears in the error) tells you which property access failed. The value to the left of that property is the problem — it’s undefined or null when your code expected an object.
Why This Happens
In JavaScript, undefined and null are not objects. They have no properties. When you write something.name, JavaScript needs something to be an object (or at least a value with properties, like a string or number). If something is undefined or null, JavaScript throws a TypeError.
Here’s the simplest reproduction:
let user = undefined;
console.log(user.name); // TypeError: Cannot read properties of undefined (reading 'name')The tricky part is that user is rarely set to undefined explicitly. It’s usually undefined because of a bug somewhere else in your code.
Under the hood, undefined and null have a primitive [[Prototype]] of null and undefined — they are the only two values in JavaScript that have no prototype chain at all. Every other value, including strings, numbers, and booleans, gets auto-boxed into an object wrapper when you access a property ("hi".length works because the string is briefly wrapped in a String object). For null and undefined, that auto-boxing step is intentionally skipped, which is why a property access on them is a TypeError rather than returning undefined. The error wording changed across engines: V8 renamed “Cannot read property ‘x’ of undefined” to “Cannot read properties of undefined (reading ‘x’)” in Chrome 92 / Node 16.6 because the new phrasing is easier to scan in long stack traces and works with destructuring.
Language and Runtime History: How Modern JS Made This Error Avoidable
Several language features that you can use to prevent this error simply did not exist a few years ago. Knowing which targets you can safely use saves you from over-engineering polyfills.
Optional chaining (?.) and nullish coalescing (??) shipped in ES2020, which means Node.js 14 (April 2020) and Chrome 80 are the practical minimum for native support. If your build pipeline still targets ES2019 or older for some legacy bundle, user?.name will be transpiled by Babel to a longer conditional expression — which still works, but you may see surprising output in the compiled bundle. Anything targeting Node 14+ or evergreen browsers can write ?. directly.
Object.hasOwn(obj, key) was added in Node.js 16.9 and Chrome 93. It is the safer replacement for obj.hasOwnProperty(key) because it works on objects created with Object.create(null) and does not throw if obj is null-prototyped. If you are guarding against undefined keys, Object.hasOwn(user ?? {}, 'name') is more robust than the older hasOwnProperty pattern.
Array.prototype.at() (ES2022, Node 16.6+) lets you write users.at(-1) instead of users[users.length - 1]. The at() method returns undefined on out-of-bounds access just like bracket notation, so it does not prevent the error, but it avoids the off-by-one bugs that often cause the error.
Logical assignment operators (??=, ||=, &&=) shipped in ES2021 / Node 15. These let you write config.host ??= 'localhost' to default a property only if it is null or undefined. They compile to the same shape as the older config.host = config.host ?? 'localhost', but they are easier to read in deep update code.
In TypeScript specifically, strictNullChecks was added in TypeScript 2.0 (September 2016) but is still opt-in inside strict: true. If you cannot find module errors or property-undefined errors in TypeScript code, double-check that strict is true in tsconfig.json — without it, the compiler treats null and undefined as members of every type, which silently masks bugs that JavaScript would surface at runtime. For more, see Fix: Object is possibly undefined in TypeScript.
Fix
1. API Response Not Yet Loaded (Async Timing)
This is the most common cause in React and other frontend frameworks. You render a component before the data it depends on has arrived.
Broken code:
function UserProfile() {
const [user, setUser] = useState(); // user is undefined initially
useEffect(() => {
fetch('/api/user')
.then(res => res.json())
.then(data => setUser(data));
}, []);
// First render: user is undefined → crash
return <h1>{user.name}</h1>;
}On the first render, user is undefined because useEffect hasn’t fired yet. Accessing user.name throws.
Fix — guard against the loading state:
function UserProfile() {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('/api/user')
.then(res => res.json())
.then(data => {
setUser(data);
setLoading(false);
});
}, []);
if (loading) return <p>Loading...</p>;
if (!user) return <p>User not found.</p>;
return <h1>{user.name}</h1>;
}You can also use optional chaining as a lighter approach:
return <h1>{user?.name ?? 'Loading...'}</h1>;But explicit loading states give a better user experience and make your intent clear to other developers.
2. Wrong Variable Name or Typo in Property Access
A simple typo causes the property access to return undefined, and then you try to read a property on that undefined value.
Broken code:
const config = {
database: {
host: 'localhost',
port: 5432,
},
};
// Typo: "databse" instead of "database"
console.log(config.databse.host);
// TypeError: Cannot read properties of undefined (reading 'host')config.databse is undefined because that key doesn’t exist. Then .host fails.
Fix: Check your property names carefully. Use TypeScript to catch this at compile time:
interface Config {
database: {
host: string;
port: number;
};
}
const config: Config = {
database: { host: 'localhost', port: 5432 },
};
console.log(config.databse.host);
// ~~~~~~~~
// Property 'databse' does not exist on type 'Config'. Did you mean 'database'?Why this matters: This error is the JavaScript equivalent of a null pointer exception. It’s the single most common runtime error in JavaScript applications. Learning to handle
undefinedandnulldefensively will eliminate a large percentage of the bugs you encounter.
3. Array Index Out of Bounds
Accessing an index that doesn’t exist returns undefined. If you then access a property on it, you get the error.
Broken code:
const users = [{ name: 'Alice' }, { name: 'Bob' }];
// Only 2 elements (index 0 and 1), but we try index 2
console.log(users[2].name);
// TypeError: Cannot read properties of undefined (reading 'name')Fix — check the array length or use optional chaining:
// Option A: bounds check
if (users.length > 2) {
console.log(users[2].name);
}
// Option B: optional chaining
console.log(users[2]?.name); // undefined (no crash)Watch out for this with .find() too — it returns undefined when no match is found:
const admin = users.find(u => u.role === 'admin');
console.log(admin.name); // TypeError if no admin exists
// Fix:
const admin = users.find(u => u.role === 'admin');
console.log(admin?.name); // undefined (no crash)4. Missing Function Parameter
When a function expects an object argument and you call it without one (or with the wrong shape), the parameter is undefined.
Broken code:
function greet(user) {
return `Hello, ${user.name}!`;
}
greet(); // TypeError: Cannot read properties of undefined (reading 'name')Fix — use a default parameter:
function greet(user = { name: 'Guest' }) {
return `Hello, ${user.name}!`;
}
greet(); // "Hello, Guest!"Or add a guard clause:
function greet(user) {
if (!user) return 'Hello, Guest!';
return `Hello, ${user.name}!`;
}In TypeScript, mark required parameters explicitly and let the compiler enforce call sites:
function greet(user: { name: string }) {
return `Hello, ${user.name}!`;
}
greet(); // Compile error: Expected 1 arguments, but got 05. Destructuring an Undefined Object
Destructuring is just property access under the hood. If the value you destructure is undefined, you get the same error.
Broken code:
function processResponse(response) {
const { data } = response; // TypeError if response is undefined
console.log(data);
}
processResponse(); // called without argumentFix — use a default value in the destructuring pattern:
function processResponse(response = {}) {
const { data } = response; // data is undefined, but no crash
console.log(data);
}Or provide a default directly in the parameter destructuring:
function processResponse({ data = null } = {}) {
console.log(data); // null (no crash)
}The = {} after the destructuring pattern is critical. Without it, calling processResponse() with no arguments still throws.
6. Deep Nested Object Access
When you chain property access like a.b.c.d, any link in that chain being undefined breaks everything that follows.
Broken code:
const order = {
customer: {
name: 'Alice',
// address is not present
},
};
console.log(order.customer.address.street);
// TypeError: Cannot read properties of undefined (reading 'street')order.customer.address is undefined, so .street throws.
Fix — optional chaining (?.):
console.log(order.customer?.address?.street); // undefined (no crash)Optional chaining short-circuits: if any part of the chain is undefined or null, the entire expression evaluates to undefined instead of throwing.
Combine with nullish coalescing (??) for a fallback value:
const street = order.customer?.address?.street ?? 'No address on file';
console.log(street); // "No address on file"Use ?? instead of || here. The || operator treats '' (empty string) and 0 as falsy and would replace them with the fallback. The ?? operator only triggers on null and undefined.
Quick Reference: Fix Patterns
Optional Chaining (?.)
Safely access nested properties. Returns undefined instead of throwing:
user?.profile?.avatar?.urlWorks with method calls and bracket notation too:
user?.getProfile?.() // safe method call
user?.['first-name'] // safe bracket accessNullish Coalescing (??)
Provide a fallback when a value is null or undefined:
const name = user?.name ?? 'Anonymous';Default Parameters
Give function parameters a fallback value:
function render(options = {}) {
const { width = 800, height = 600 } = options;
}Guard Clauses / Early Returns
Bail out of a function early when data is missing:
function updateUser(user) {
if (!user) return;
if (!user.profile) return;
user.profile.lastUpdated = Date.now();
}React-Specific Patterns
Conditional Rendering
Only render a component when the data it needs is available:
function Dashboard({ user }) {
return (
<div>
<h1>Dashboard</h1>
{user && <UserProfile user={user} />}
{user?.posts?.length > 0 && <PostList posts={user.posts} />}
</div>
);
}The useEffect Data Fetching Pattern
The standard pattern for fetching data in a React component:
function OrderDetails({ orderId }) {
const [order, setOrder] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
let cancelled = false;
fetch(`/api/orders/${orderId}`)
.then(res => {
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
})
.then(data => {
if (!cancelled) setOrder(data);
})
.catch(err => {
if (!cancelled) setError(err.message);
});
return () => { cancelled = true; };
}, [orderId]);
if (error) return <p>Error: {error}</p>;
if (!order) return <p>Loading...</p>;
return (
<div>
<h2>Order #{order.id}</h2>
<p>Status: {order.status}</p>
<p>Total: ${order.total}</p>
</div>
);
}Key points:
- Initialize state to
null, notundefined. This makes your intent clear — the data hasn’t loaded yet. - Guard the render with a null check before accessing properties.
- Handle errors so a failed fetch doesn’t leave the component in a broken state.
- Use a cleanup flag (
cancelled) to avoid setting state on an unmounted component when theorderIdprop changes.
Still Not Working?
Place console.log Before the Failing Line
The error stack trace tells you the line number. Add a console.log directly before that line to inspect the value:
console.log('user value:', user);
console.log('user type:', typeof user);
console.log('user is null:', user === null);
console.log('user is undefined:', user === undefined);
console.log(user.name); // this is the line that throwsThis tells you whether the value is undefined, null, or something else entirely (like a string or number when you expected an object).
Use the Debugger
Add a debugger; statement right before the crash. When DevTools is open, execution pauses there and you can inspect every variable in scope:
debugger;
console.log(user.name);Or set a breakpoint directly in the Sources panel of Chrome DevTools.
Check the Network Tab for API Issues
If the error involves data from an API:
- Open DevTools and go to the Network tab.
- Find the API request and check its status code. A
404or500means the data you expected didn’t come back. - Click the request and check the Response tab. Verify the JSON structure matches what your code expects. A common issue: the API returns
{ data: { users: [...] } }but your code accessesresponse.usersinstead ofresponse.data.users.
Check for Race Conditions
If the error happens intermittently, you likely have a timing issue. Two things to check:
- Are you accessing state before
useEffectfires? The component renders once with initial state before effects run. - Are you accessing a value that depends on another async operation completing first? Chain your promises or use
async/awaitto ensure ordering.
Check the Error Stack Trace
The stack trace shows you the exact chain of function calls that led to the error. Read it from top to bottom:
TypeError: Cannot read properties of undefined (reading 'street')
at formatAddress (src/utils/format.js:12:28)
at UserCard (src/components/UserCard.jsx:45:22)
at renderWithHooks (react-dom.development.js:16305:18)Line 12 of format.js is where it crashed. Line 45 of UserCard.jsx is where formatAddress was called. Check both locations — the bug might be in how the data was passed, not in the function itself.
Source maps are pointing to the wrong line
If the stack trace lands on a line that does not look like the failing code, your source map is stale. Bundlers cache source maps aggressively. Run a clean build (rm -rf dist && npm run build or your equivalent) and reload with cache disabled in DevTools. In Next.js or Vite, set sourcemap: true in the build config and confirm the .map files are actually being served.
A Proxy or getter is throwing internally
If you see Cannot read properties of undefined on a property that you can see in the DevTools Object inspector, the property is probably defined by a getter that itself throws or returns undefined. Common culprits are MobX, Vue’s reactivity proxies, and ORM lazy-loaded relations. Wrap the access in a try/catch to see the underlying error, or call the getter explicitly via Object.getOwnPropertyDescriptor(obj, 'name').get?.call(obj) to inspect what it returns.
A library returned undefined for a removed export
When you upgrade a dependency, an export that previously existed may have been renamed or removed. The import becomes undefined, and the next property access throws. Check the library’s changelog for the version range you bumped through. The TypeScript compiler would normally catch this with Cannot find name, but plain JavaScript happily lets the undefined import propagate. If the import itself is failing rather than returning undefined, see Fix: Cannot find module in Node.js.
React 18 strict mode double-render reveals a stale closure
React 18’s strict mode invokes effects twice in development. If your effect mutates an external object on first run and reads it on second run, the read can see undefined for cleanup-related state. Make effects idempotent and use the cleanup function to undo any mutation. This is one of the subtler causes of “cannot read properties of undefined” errors that only appear in development.
Related: Fix: Port 3000 Is Already in Use. For the TypeScript equivalent of this runtime error, see Fix: Object is possibly undefined.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: i18next Not Working — Translations Missing, Language Not Switching, or Namespace Errors
How to fix i18next issues — react-i18next setup, translation file loading, namespace configuration, language detection, interpolation, pluralization, and Next.js integration.
Fix: Mapbox GL JS Not Working — Map Not Rendering, Markers Missing, or Access Token Invalid
How to fix Mapbox GL JS issues — access token setup, React integration with react-map-gl, markers and popups, custom layers, geocoding, directions, and Next.js configuration.
Fix: React PDF Not Working — PDF Not Rendering, Worker Error, or Pages Blank
How to fix react-pdf and @react-pdf/renderer issues — PDF viewer setup, worker configuration, page rendering, text selection, annotations, and generating PDFs in React.
Fix: React Three Fiber Not Working — Canvas Blank, Models Not Loading, or Performance Dropping
How to fix React Three Fiber (R3F) issues — Canvas setup, loading 3D models with useGLTF, lighting, camera controls, animations with useFrame, post-processing, and Next.js integration.