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

Quick answer

You read a property of a value that is null or undefined. The (reading 'X') part names the property — the value before .X is the empty one. Use optional chaining value?.X (+ ?? fallback), guard the value, and for the DOM/React make sure it exists before you read it. In TypeScript, TS2532 catches this at compile time.

The exact error string

const user = null;
console.log(user.name);
// Uncaught TypeError: Cannot read properties of null (reading 'name')

const data = {};
data.items.length;
// Uncaught TypeError: Cannot read properties of undefined (reading 'length')
// (older engines: "Cannot read property 'length' of undefined")

How to find which value is null (in 30 seconds)

The message tells you exactly where to look. The property in (reading 'X') is what you tried to access — so the value immediately before .X is the null/undefined one, and the property name hints at the type it should have been:

order.customer.address.city
// TypeError: Cannot read properties of undefined (reading 'city')
//   -> 'address' is undefined (city is read on address)
//   -> so order.customer exists, but .address does not

// confirm by logging the chain, or narrow with optional chaining:
console.log(order.customer);          // ok?
console.log(order.customer.address);  // undefined -> found it

The stack trace's file:line:column points at the exact access; (reading 'length') or (reading 'map') means an array was missing, (reading 'then') means a non-promise, and (reading 'current') usually means a React ref (below).

Fix 1: optional chaining (quickest)

user?.name;                       // undefined instead of throwing
data?.items?.length ?? 0;         // safe down a chain, with a fallback
order?.customer?.address?.city;   // stops at the first null/undefined

Fix 2: guard before you use it

if (user) {
  console.log(user.name);         // user is non-null here
}

const items = data.items ?? [];   // default so .map/.length are safe
items.forEach(/* ... */);

Fix 3: DOM — element not found

getElementById/querySelector return null when nothing matches, and run too early if the script is in <head> before the element exists:

const el = document.getElementById("app");
if (!el) throw new Error("#app not found");   // or handle gracefully
el.innerHTML = "ok";

// run after the DOM is parsed:
// <script src="app.js" defer></script>  or DOMContentLoaded

Fix 4: async data not loaded yet

Before a fetch resolves, your value is often null/undefined — render defensively for the loading state:

if (!data) return "Loading...";   // handle the empty first pass
return data.user?.name ?? "Anonymous";

const { items = [] } = response ?? {};   // destructure with defaults

Worked example: an API field that isn't there

The crash often isn't "data hasn't loaded" but "the field you assumed exists is missing or nested differently." Inspect the real shape before you trust it:

const res = await fetch("/api/order/42");
const order = await res.json();
renderCity(order.customer.address.city);
// TypeError: Cannot read properties of undefined (reading 'city')

// The API actually returned { "customer": { "address": null } } for guest orders.
// Inspect the payload, then read defensively:
const city = order.customer?.address?.city ?? "—";

Paste the response into the JSON Formatter to see which fields really exist and how deep they are. If the request itself failed, the body is an error page, not your object — check the HTTP status first.

Cannot read properties of null in React

// 1) refs are null until mount
const ref = useRef(null);
ref.current.focus();              // ❌ null on first render
useEffect(() => { ref.current?.focus(); }, []);   // ✅ after mount, guarded

// 2) state that starts empty
const [user, setUser] = useState(null);
return <span>{user.name}</span>;   // ❌ null before the fetch resolves
return <span>{user?.name ?? "…"}</span>;   // ✅

// 3) mapping data that may be undefined
{items?.map(i => <li key={i.id}>{i.name}</li>)}   // ✅ guard the array

Common variants of this message

MessageWhat was emptyUsual cause
... (reading 'length')an array/stringa list that was never set / API omitted it
... (reading 'map')an arrayrendering before data loads
... (reading 'name') / any fieldan objectmissing or differently-nested field
... of null (reading 'X')explicit nullgetElementById, a DB null
... (reading 'current')a React refreading ref.current before mount
... (reading 'then')a non-promiseawaiting a function that returned nothing

Debugging checklist

Frequently Asked Questions

What does the "(reading 'length')" or "(reading 'map')" part tell me?

It names the property you tried to access, which tells you what type the missing value should have been. (reading 'length') or (reading 'map') means an array or string was undefined; (reading 'name') means an object was null/undefined. The value before that property is the one that is empty.

How do I find which part of a.b.c.d is null?

The (reading 'X') names the last good step: whatever you accessed X on is the null/undefined one. Log the chain piece by piece, or temporarily add optional chaining and see where the result becomes undefined. The stack trace's file:line:column points to the exact access.

Why does it only happen in production or after a build?

Usually because production hits real, varied data (an omitted field, an empty list) that your local sample didn't, or timing differs so data isn't loaded yet. Minification also renames variables, making the stack harder to read — ship source maps so the trace points to your original code.

Why does it happen with useRef().current in React?

useRef(null).current is null until the element mounts, so reading ref.current.focus() during the first render or in a top-level statement throws. Access it inside an effect or event handler, and guard it: ref.current?.focus().

Does optional chaining hurt performance?

No, not meaningfully. ?. compiles to a cheap null/undefined check — the cost is negligible compared to almost anything else in your code. Do not avoid it for performance; the readability and crash-safety are worth far more than the micro-cost.

How do I prevent this across the whole codebase?

Use TypeScript with strictNullChecks, which flags the access at compile time as TS2532 before it can crash at runtime, and validate API data at the boundary (a schema check or generated types) so missing fields are caught where data enters, not deep in a component.

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 JSONPath Tester All Error References
About the author

Pasindu Ishan is a software developer based in Sri Lanka. He builds privacy-first developer tools at JSON Dev Tools.