Start by identifying which value is missing

In JavaScript, null and undefined are related but not interchangeable. null is commonly used to represent an intentional absence of a value. undefined often means a value was never assigned, a property does not exist, or a function finished without returning anything. Either can cause an error when code tries to read a property from it.

Read the error message and locate the expression on the reported line. For example, in user.profile.name, the failing value might be user or user.profile. The message may say which value was null or undefined, but it does not necessarily tell you why. Avoid changing several lines at once: first find the exact step in the property path that fails.

Reproduce the problem with a small example

The following example runs in the developer-tools console of a modern browser. It uses basic JavaScript syntax supported by modern browsers; no package or build tool is required. Open the console, paste the lines in order, and observe where the error occurs.

const user = { profile: null }; console.log(user); console.log(user.profile); console.log(user.profile.name);

The first log shows the object, and the second shows null. The final line fails because it attempts to read name from null. Now replace the first line with const user = {}; and run the lines again. The second log shows undefined instead: profile is not present on that object. Both versions fail at the last line, but they point to different questions. Was profile deliberately set to null, or was it never supplied?

Trace the value backward, one step at a time

In your own code, pause immediately before the failing expression. Use a breakpoint in browser developer tools, or add temporary logs that inspect each step separately: the containing object, then the property you expect, then the operation that reads from it. At a breakpoint, check the current variables and call stack. The call stack shows how execution reached this point; stepping backward through the code's inputs and assignments helps you find where the unexpected value entered.

Search for every place the variable or property is assigned. Follow the path from its source, such as a function argument, form input, or parsed data, through any transformations. If an object comes from a function, inspect what that function returns on every path. A function with no return statement produces undefined. A conditional branch that returns a value in one case but not another can produce the same surprise.

Logs can be misleading when you inspect an object later, after other code has changed it. At the suspicious line, log the specific primitive or property value you need, or pause execution to inspect its state at that moment. Remove temporary logs when you have found the cause.

Check assumptions at boundaries

Many missing values originate at a boundary where your code accepts something it did not create. An optional form field may be empty; a lookup may find no match; data loaded from storage may not have the shape you expected. Before reading a nested property, decide what shapes are valid. Is profile required, allowed to be null, or allowed to be absent? These are different contracts, even if the next line would fail in the same way.

To distinguish an absent property from one explicitly set to undefined, you can use Object.prototype.hasOwnProperty.call(user, "profile"). That test checks whether user owns the property; it does not prove the property's value is usable. Also check arguments passed into a function rather than assuming callers always provide them. If the source is external data, validate the parts you need before using them.

Fix the cause, then handle expected absence

If profile is required, fix the code that creates or supplies the user object, and report an invalid input where it enters your program. If a missing profile is normal, handle that case explicitly: const name = user.profile == null ? "Guest" : user.profile.name;. Here, == null is a deliberate JavaScript shorthand that matches both null and undefined. Use it only when those two cases should receive the same treatment.

Optional chaining can make an expected absence concise: const name = user.profile?.name ?? "Guest";. This syntax is available in modern browsers and recent Node.js releases, but check your project's supported JavaScript version before using it. It prevents a property-read error and supplies a fallback; it does not explain why profile was missing. Adding it everywhere can conceal a broken assumption.

After a fix, test at least three cases: a valid profile, a deliberately missing profile, and the input that originally failed. Confirm that the result is appropriate in each case, not merely that the error disappears. The most useful debugging question is not “How do I stop this line from throwing?” but “Where was this value supposed to come from, and what should happen when it does not arrive?”

Back to category ↗