TypeError: Cannot set properties of undefined (setting 'X')

Quick answer

You wrote obj.a.b = value, but obj.a is undefined — there's no object there to set .b on. This is the write-side version of Cannot read properties of undefined: every intermediate level in a nested write must already exist. Initialize the missing parent to {} (or []) before writing to it.

The exact error string

const result = {};
result.stats.count = 1;
// Uncaught TypeError: Cannot set properties of undefined (setting 'count')
//   -> result.stats is undefined, so there's nowhere to put "count"

What it actually looks like

Chrome DevTools console showing a red error row reading Uncaught TypeError: Cannot set properties of undefined (setting 'host'), sourced to app.js line 3.
Captured from Chrome 152. The verb is setting, not reading — you were writing into a nested path whose parent had never been created. Optional chaining will not save you here: ?. guards reads, and a write still needs the parent to exist.

Read vs write: why this one always throws

Reading result.stats when it doesn't exist just gives you undefined — you can keep going (and chain into a crash later, as in the "reading" version of this error). Writing has no such fallback: JavaScript needs a real object to attach the new property to, and if the parent is undefined, there's nowhere to put it, so it throws immediately at the assignment.

Cause 1: writing into a nested path that isn't built yet

const config = {};
config.server.port = 3000;
// ❌ config.server is undefined

const config = {};
config.server = config.server || {};   // ✅ initialize the parent first
config.server.port = 3000;

// or build the shape up front:
const config = { server: { port: 3000 } };   // ✅

Cause 2: grouping array items by a dynamic key

const groups = {};
for (const item of items) {
  groups[item.category].push(item);
  // ❌ groups[item.category] is undefined the first time this category appears
}

const groups = {};
for (const item of items) {
  groups[item.category] = groups[item.category] || [];   // ✅ initialize the bucket
  groups[item.category].push(item);
}

Cause 3: mutating nested React/Redux state directly

// ❌ direct mutation, and settings may not exist on the current state
state.user.settings.theme = "dark";

// ✅ build a new object, spreading each level you touch
setState(prev => ({
  ...prev,
  user: {
    ...prev.user,
    settings: { ...prev.user.settings, theme: "dark" },
  },
}));

Cause 4: a typo'd or wrong-cased intermediate key

const data = { userProfile: {} };
data.userprofile.name = "Ada";
// ❌ "userprofile" (lowercase p) doesn't exist — data.userProfile does

data.userProfile.name = "Ada";   // ✅ match the actual key exactly

Fix: nullish-assignment shortcut

Modern JavaScript's ??= operator initializes a value only if it's currently null/undefined, which is a compact way to guarantee the parent exists right before you write to it:

const config = {};
config.server ??= {};     // sets {} only if config.server is null/undefined
config.server.port = 3000;   // ✅ now safe

Optional chaining cannot fix this one

The reflex for the reading version of this error is optional chaining, and it works perfectly there. Reaching for it on the write side does not just fail at runtime — the file will not parse:

const value = config?.database?.host;   // ✅ reading — undefined, no throw

config?.database.host = "localhost";
// ❌ SyntaxError: Invalid left-hand side in assignment

Verified on Node v24.15.0. This is deliberate, and the reasoning is worth knowing: ?. means "stop and produce undefined if this is nullish", and there is no sensible way to assign a value to undefined. The specification therefore forbids an optional chain anywhere on the left of an assignment. A SyntaxError rather than a TypeError is the clue — the whole module fails to load, and the line number points at the assignment.

Build the path instead: the ??= one-liner

Since you cannot guard the write, you have to guarantee the parent exists first. Logical nullish assignment (??=) does this in one expression per level, and it only writes when the target is null or undefined, so existing data is never clobbered:

const config = {};

config.database ??= {};        // create the parent only if missing
config.database.host = "localhost";   // ✅ safe now
// config is { database: { host: "localhost" } }

For the grouping case — building { [key]: [...] } from a list — the same pattern collapses the usual four-line if into one, and Object.groupBy() replaces it entirely where your runtime has it:

// before: throws on the first unseen key
byStatus[order.status].push(order);          // ❌ Cannot set properties of undefined

// after:
(byStatus[order.status] ??= []).push(order); // ✅ creates the array on first use

// or, Node 21+ / Chrome 117+:
const byStatus = Object.groupBy(orders, o => o.status);

Where the path is deep and comes from configuration rather than code, a Map or a single flat key ("database.host") is often a better answer than nesting objects you then have to defensively create at every level.

Common variants at a glance

PatternMissing parentFix
obj.a.b = xobj.aobj.a ??= {} before writing
groups[key].push(x)groups[key]initialize the bucket first
direct nested state mutationa state sub-objectrebuild with spreads, don't mutate
typo'd/mis-cased keythe wrong key entirelymatch the real property name

Debugging checklist

Frequently Asked Questions

What does 'Cannot set properties of undefined (setting X)' mean?

You tried to write obj.a.b = value, but obj.a itself is undefined — there is no object there to set a property on. This is the write-side counterpart of "Cannot read properties of undefined": the same missing-parent problem, encountered while assigning instead of reading.

Why does building up a nested object fail like this?

Writing to a nested path requires every intermediate level to already be an object — result.stats.count = 1 needs result.stats to exist first. Unlike reading (which just gives undefined and lets you continue), writing to a property of undefined throws immediately, because there is nowhere to store the value.

How do I initialize a nested object safely?

Check and create each missing level before writing the final value: if (!obj.a) obj.a = {}; then obj.a.b = value. Or build the whole structure with a single object literal up front if you know its shape ahead of time, rather than assigning into it level by level.

Why does this happen when grouping array items into an object?

A common reduce pattern groups[item.category].push(item) fails the first time a new category key is seen, because groups[item.category] is still undefined. Initialize the bucket first: groups[item.category] = groups[item.category] || []; then push.

Why does this happen with React state?

Directly mutating nested state — state.user.settings.theme = 'dark' — both violates React's immutability expectations and throws this error if settings doesn't exist yet on the current state object. Use setState with a new object (spreading each level) instead of writing into the existing state tree.

How do I fix this quickly?

Find the parent in the write path that is undefined (the message doesn't say which — trace the chain manually or log each level), initialize it to an empty object or array before the write, or use a library/utility (like lodash's set, or optional chaining with nullish assignment obj.a ??= {}) to create intermediate levels safely.

References

More JavaScript & runtime errors

Browse the full reference for JavaScript, Node.js, and database errors — exact message, cause, and fix.

All Error References Cannot read properties of undefined 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.