What you'll learn
Quick Answer
This error means you tried to read a property from something that is undefined or null. The fix is never at the line that threw — it is wherever that value was supposed to be set. The five usual causes are a typo in the property name, data that has not arrived yet from an API, an array index that does not exist, a function that returned nothing, and a lost this binding. Use optional chaining to read safely, but find the real source rather than silencing it.
What the Error Actually Means
Modern browsers word it slightly differently, but the meaning is identical.
TypeError: Cannot read property 'name' of undefined // older Chrome
TypeError: Cannot read properties of undefined (reading 'name')
TypeError: undefined is not an object (evaluating 'user.name') // SafariAll of them say the same thing: you asked for .name, but the thing on the left of the dot was undefined.
The critical insight is that user is the problem, not name. Beginners stare at the property, but the property is innocent — it was never reached. Something upstream failed to produce an object.
Read the message backwards to find your suspect:
Cannot read properties of undefined (reading 'city')
^^^^^^^^^ ^^^^
the problem what you asked for
// If the code is user.address.city
// then 'address' is undefined — so look at how 'user' was builtThat single habit — identifying which link in the chain is undefined — solves most of these in seconds.
Cause 1: A Typo or Wrong Property Name
The simplest cause, and worth ruling out first because it costs nothing to check.
const user = { firstName: 'Riya', address: { city: 'Pune' } };
console.log(user.firstname.length); // TypeError
// ^^^^^^^^^ lowercase n — this property does not existJavaScript property names are case sensitive, and reading a missing property does not throw — it quietly returns undefined. The error only appears one step later when you try to use that undefined.
That delay is what makes the error confusing. The mistake was on firstname; the crash is on .length.
The same applies to API responses where the field name differs from what you assumed — user_name versus userName, or data nested one level deeper than expected.
The fastest check is to log the parent object rather than the property:
console.log(user); // see what is actually there
console.log(Object.keys(user)); // exact spelling of every keyDo not log user.firstname — that just prints undefined and tells you nothing new.
Cause 2: The Data Has Not Arrived Yet
This is the version that dominates real applications, especially in React.
function Profile({ userId }) {
const [user, setUser] = useState(); // undefined on first render
useEffect(() => {
fetch(`/api/users/${userId}`)
.then(r => r.json())
.then(setUser);
}, [userId]);
return <h1>{user.name}</h1>; // TypeError on the very first render
}The component renders before the fetch resolves. On that first pass user is undefined, and reading .name throws.
The fix is to handle the loading state explicitly rather than hoping the data is there:
const [user, setUser] = useState(null);
if (!user) return <p>Loading…</p>;
return <h1>{user.name}</h1>;Initialising state to a sensible empty shape also helps — useState([]) for a list means .map works immediately instead of crashing.
The same pattern appears outside React whenever code runs before an async result: reading a variable that a .then will populate later, or touching a DOM element before the page has parsed it.
Causes 3 and 4: Missing Array Items and Silent Returns
An index or search that found nothing. Array methods that fail do not throw — they return undefined.
const users = [{ name: 'Riya' }];
console.log(users[5].name); // TypeError — index 5 does not exist
const found = users.find(u => u.name === 'Amit');
console.log(found.name); // TypeError — find returned undefinedfind, pop on an empty array, and match with no match all behave this way. Always check the result before using it:
const found = users.find(u => u.name === 'Amit');
if (!found) return; // or handle the miss properly
console.log(found.name);A function that returns nothing. A JavaScript function without an explicit return gives back undefined.
function getUser(id) {
if (id) {
return { id, name: 'Riya' };
}
// no else — returns undefined when id is falsy
}
getUser(0).name; // TypeError, because 0 is falsyThe arrow-function version of this is subtle and very common: adding braces around a body silently removes the implicit return.
const double = n => ({ value: n * 2 }); // returns the object
const broken = n => { value: n * 2 }; // returns undefined
Fixing It Properly
Optional chaining is the modern tool. ?. stops the whole expression and returns undefined instead of throwing when the left side is null or undefined.
user?.address?.city // undefined instead of a crash
users?.[0]?.name // works for indexes too
callback?.() // only calls it if it existsPair it with the nullish coalescing operator to supply a fallback:
const city = user?.address?.city ?? 'Unknown';Use ?? rather than || here. || also replaces empty strings and zero, so count || 10 turns a legitimate 0 into 10. ?? only replaces null and undefined.
But do not let optional chaining hide a real bug. This is the important caveat. If user should always exist by that point, user?.name silently produces undefined and the failure moves somewhere further away, where it is harder to diagnose. Use ?. where a value is legitimately optional — and a guard clause or a fixed data flow where it is not.
For debugging, set the browser devtools to pause on exceptions. It stops at the throwing line with the whole scope available, which beats scattering console.log calls.
