TypeError: Cannot read properties of undefined (reading 'X')

Quick answer

You read a property of a value that was never assigned — a missing object key, a function that fell through without a return, or an array index past the end. The (reading 'X') part names the property; the value before .X is undefined. Use optional chaining value?.X (+ ?? fallback), then trace back to why the value is missing.

The exact error string

const user = {};
console.log(user.profile.name);
// Uncaught TypeError: Cannot read properties of undefined (reading 'name')
//   -> user.profile is undefined (no such key on user)

function getUser() { /* no return */ }
console.log(getUser().name);
// Uncaught TypeError: Cannot read properties of undefined (reading 'name')
//   -> getUser() returned undefined

What it actually looks like

Chrome DevTools console showing a red error row reading Uncaught TypeError: Cannot read properties of undefined (reading 'email'), sourced to app.js line 3.
Captured from Chrome 152. The parenthesised name is the property you tried to read, which means the undefined value is whatever sits immediately to its left — in user.profile.email that is user.profile, not user and not email. Reading the message this way skips most of the debugging.

How this differs from the "null" version

This is the same rule as Cannot read properties of null — you can't read a property off a non-object — but the empty value tells you something different. undefined almost always means "this was never assigned": a missing object key, an unreturned function, an out-of-range array index. null usually means "explicitly set to nothing": getElementById finding no match, a database NULL, a React useState(null). Knowing which one you have narrows down where to look first.

Cause 1: a missing object key

const user = { id: 1, name: "Ada" };
console.log(user.profile.avatarUrl);
// ❌ user.profile doesn't exist -> undefined.avatarUrl

console.log(user.profile?.avatarUrl ?? "/default-avatar.png");   // ✅

Cause 2: destructuring a field that isn't there

const { address } = order;   // order has no 'address' key -> undefined
console.log(address.city);
// ❌ Cannot read properties of undefined (reading 'city')

const { address } = order;
console.log(address?.city ?? "Unknown");   // ✅

Cause 3: a function that didn't return anything

function findUser(id) {
  if (id > 0) {
    return { id, name: "Ada" };
  }
  // ❌ no else -> falls through, implicitly returns undefined
}
console.log(findUser(-1).name);   // Cannot read properties of undefined (reading 'name')

function findUser(id) {
  if (id > 0) return { id, name: "Ada" };
  return null;   // ✅ explicit "not found" value
}

Cause 4: reading past the end of an array

const items = ["a", "b", "c"];
console.log(items[5].length);
// ❌ items[5] is undefined (index out of range) -> .length throws

const found = items.find(i => i === "z");
console.log(found.length);
// ❌ find() returned undefined (no match)

console.log(items[5]?.length ?? 0);        // ✅
console.log(found?.length ?? 0);           // ✅

Worked example: an API field that's optional

The most common real-world trigger is trusting an API shape that isn't guaranteed:

const res = await fetch("/api/orders/42");
const order = await res.json();
console.log(order.shipping.trackingNumber);
// ❌ "shipping" is only present once the order ships — undefined until then

// Inspect the real shape first, then read defensively:
const tracking = order.shipping?.trackingNumber ?? "Not shipped yet";

Paste the raw response into the JSON Formatter to see exactly which fields exist on a given response before you write the access chain.

The optional-chaining mistake that still throws

Adding a single ?. at the front of a chain is the most common attempted fix, and it is the one that keeps the bug. ?. guards only the link it is attached to — once that link is non-nullish, the rest of the chain evaluates exactly as before:

const res = {};            // res exists; res.data does not

res?.data.email;
// ❌ TypeError: Cannot read properties of undefined (reading 'email')
//    res is fine, so ?. short-circuits nothing — then .email runs on undefined

res?.data?.email;          // ✅ undefined — every link guarded
(res.data ?? {}).email;    // ✅ undefined — same result, no chaining

Verified on Node v24.15.0. The rule: the ?. has to sit at the link that is actually missing, and the message tells you which one that is — (reading 'email') means the value immediately to the left of .email was the undefined one. Guard there, not at the start of the expression.

Guarding every link is not automatically right either. a?.b?.c?.d silently produces undefined whether the data is legitimately absent or your API contract just changed underneath you — which converts a loud crash into a value that spreads. Guard the links that are genuinely optional, and let the ones that should always exist throw.

Common variants of this message

MessageWhat was undefinedUsual cause
... (reading 'X') on an objecta missing keyoptional/absent API field
... (reading 'name') after destructurea non-existent fieldtypo or wrong nesting level
... (reading 'X') on a function callthe return valuemissing return on some path
... (reading 'length'/'map') on an indexan array slotout-of-range index or no match
... (reading 'X') on a paraman omitted argumentoptional parameter never passed

Debugging checklist

Frequently Asked Questions

Is 'Cannot read properties of undefined' different from the null version?

Same underlying rule (you can't read a property of a non-object), different value. undefined almost always means "this was never assigned" — a missing object key, a function that returned nothing, a destructured field that doesn't exist. null usually means "explicitly set to nothing" — getElementById, a database NULL, useState(null). The distinction tells you where to look.

Why is my destructured variable undefined?

const { a } = obj destructures whatever key a holds on obj — if obj has no property named a, you get undefined, not an error, and the error only appears later when you use a.b. Log obj (or check its keys) to confirm the field actually exists and is spelled/cased the same as in your destructure.

Why does a function call return undefined?

A function with no return statement, a return with nothing after it, or a return that only executes on some code paths (an if without an else) all implicitly return undefined. If you then chain a property off the call result — fn().value — and the function fell through without returning, you get this error.

Why does an array element read as undefined?

Indexing past the end of an array (arr[10] on a 3-item array), a "hole" from a sparse array, or find()/.at() finding no match all return undefined for that slot — arrays don't throw on out-of-range access, they just hand back undefined, and the error only surfaces when you read a property off that missing element.

How do I fix Cannot read properties of undefined quickly?

Optional chaining is the fastest fix: value?.prop instead of value.prop, combined with a ?? fallback for a default. For the real fix, trace back to why the value is undefined — a missing API field, an off-by-one array index, or a function path that forgot to return — and address that source.

How do I prevent this at compile time?

TypeScript's strictNullChecks flags a possibly-undefined access as TS2532 before your code ever runs. Validating external data (API responses, JSON.parse results) at the boundary catches missing fields before they propagate.

References

Is the data shaped how you think?

Paste the API response into the formatter to see exactly which fields exist and how they're nested — nothing is uploaded to a server.

JSON Formatter All Error References HTTP Status Codes
About the author

Pasindu Ishan is a Senior Software Engineer working on data streaming systems, which means most days end at a JSON payload that will not parse. The JavaScript references here are checked against a real runtime before being written up. He builds the free in-browser tools at JSON Dev Tools.