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
| Message | What was empty | Usual cause |
|---|---|---|
... (reading 'length') | an array/string | a list that was never set / API omitted it |
... (reading 'map') | an array | rendering before data loads |
... (reading 'name') / any field | an object | missing or differently-nested field |
... of null (reading 'X') | explicit null | getElementById, a DB null |
... (reading 'current') | a React ref | reading ref.current before mount |
... (reading 'then') | a non-promise | awaiting a function that returned nothing |
Debugging checklist
- ✓ Read
(reading 'X')— the value before.Xis the null/undefined one - ✓ Quick read? Optional chaining
?.(+??fallback) - ✓ Doing work with it? Guard with
if (value)or a default - ✓ DOM? Confirm the element exists and the script runs after load (
defer) - ✓ React? Guard
ref.current?.and typed-null state; access refs in effects - ✓ API field missing? Check the real shape in the JSON Formatter
- ✓ Prevent it codebase-wide with TypeScript
strictNullChecks(TS2532)
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.