Fix Common Errors

Fix 'Cannot read properties of undefined' in JS

'Cannot read properties of undefined' is JavaScript's most common TypeError. Learn its causes and fix it with optional chaining and null guards.

TypeError: Cannot read properties of undefined (reading 'x') is the most common runtime error in JavaScript, and it means exactly what it says: you tried to read a property off a value that was undefined (or null). The fix is rarely hard once you find the culprit — the hard part is finding which value was empty, and why. This guide covers both.

What the error means

In JavaScript, only undefined and null throw when you access a property on them. So this line:

const city = user.address.city;

throws Cannot read properties of undefined (reading 'city') when user.address is undefined. The bracket in the message — (reading 'city') — tells you the property you tried to reach, which points straight at the empty value: user.address.

Older V8 versions phrased this as Cannot read property 'city' of undefined. It's the same error — Chrome/Node just reworded it. Both mean a property access on undefined or null.

The four usual causes

Nearly every occurrence traces back to one of these:

  1. An API returned less than you expected. response.data.user is undefined because the payload shape changed or the request failed.
  2. Async data isn't there yet. A React component renders before fetch resolves, so data.items is read while data is still undefined.
  3. A typo or wrong assumption about structure. user.adress (misspelled) or assuming an array where you got an object.
  4. An array method found nothing. arr.find(...) returned undefined, then you read a property off the result.

How to fix it

Guard with optional chaining

Optional chaining (?.) short-circuits to undefined instead of throwing:

const city = user?.address?.city; // undefined if either is missing, no throw

Pair it with the nullish coalescing operator to supply a default:

const city = user?.address?.city ?? "Unknown";

Validate at the boundary

Optional chaining hides the symptom; it doesn't explain why the data was missing. When the value should always exist, assert it at the edge (right after the fetch) so you fail loudly and early:

const res = await fetch("/api/user");
if (!res.ok) throw new Error(`user request failed: ${res.status}`);
const user = await res.json();
if (!user?.address) throw new Error("user.address missing in API response");

In React, handle the loading state

The async version is almost always a missing loading guard:

if (!data) return <Spinner />;   // don't touch data.items until it exists
return <List items={data.items} />;

Finding the culprit in production

Locally you have a debugger. In production you have a minified stack trace and a user who's already gone. This is where error tracking earns its keep: it captures the exact stack frame, the breadcrumbs that led there, and the affected user — so you see that user.address was undefined for logged-out users on the checkout page, not just that it happened somewhere.

Optional chaining everywhere is a trap. a?.b?.c?.d silences the error but lets bad data flow deeper into your app, where it fails somewhere less obvious. Guard where the value is allowed to be missing; assert where it isn't.

With source-mapped stack traces, the frame points at your original code — checkout.tsx:42 — instead of index-4f9a.js. From there the fix is usually a one-liner. For the general approach to tracking down runtime errors you can't reproduce locally, see how to debug production errors, and for its close cousin, undefined is not a function.

Start tracking errors in minutes

Stop guessing which value was undefined. LightTrace captures the exact frame, user, and breadcrumb trail for every production error.

Fix your next production error faster

Point any Sentry SDK at LightTrace — free up to 5,000 events/month.