⚡ Fastest fix
You called Object.keys/values/entries/assign with null or undefined. Those methods refuse to coerce an empty value into an object — default it with ?? {} right at the call site:
Object.keys(value ?? {}); // ✅ works whether value is an object, null, or undefined
Object.entries(data.profile ?? {});
What you're seeing
Object.keys(undefined);
// Uncaught TypeError: Cannot convert undefined or null to object
Object.entries(response.data.profile);
// Uncaught TypeError: Cannot convert undefined or null to object
// -> response.data.profile is null for this record
The message doesn't say which call site or variable — the stack trace's top frame names the file:line, and that's the exact value that turned out to be empty.
30-second triage
- Crashes on some records but not others? → Fix 1 (default the value) — a field is optional/nullable
- Happens right after a fetch/API call? → Fix 1 + inspect the real payload
- Using
Object.assign(target, ...)specifically? → Fix 2 (target vs source) - Want it to never happen again, codebase-wide? → Fix 3 (default at the boundary)
Fix 1 — Default the value at the call site (most common)
When: a field is sometimes an object, sometimes null/undefined.
const profile = response.data.profile; // null for guest orders
Object.keys(profile);
// ❌ Cannot convert undefined or null to object
Object.keys(profile ?? {}); // ✅ [] when profile is missing
Object.entries(profile ?? {}).forEach(([k, v]) => { /* ... */ });
Paste the raw response into the JSON Formatter to confirm which records actually have a null in that field before you decide how to default it.
Fix 2 — Object.assign: only the target throws, not the sources
When: the error comes from Object.assign(...) specifically.
Object.assign(maybeNull, { a: 1 });
// ❌ throws — maybeNull is the TARGET (first argument), and it's null
Object.assign({}, maybeNull, { a: 1 });
// ✅ fine — null/undefined SOURCES are simply skipped, contribute nothing
const merged = Object.assign({}, maybeNull, overrides); // ✅ safe pattern
Only the first argument (the target) is coerced with ToObject and throws on null/undefined. Always give Object.assign a literal {} as the target when any source might be empty.
Fix 3 — Default once, at the boundary
When: the same field gets read with Object.keys/values/entries in many places.
// normalize once, right where the data enters your code:
function normalizeOrder(raw) {
return { ...raw, profile: raw.profile ?? {} };
}
const order = normalizeOrder(await res.json());
Object.keys(order.profile); // ✅ always safe from here on
Why this happens
Object.keys, Object.values, Object.entries, and Object.assign's target all internally call the abstract operation ToObject on their argument before doing anything else. ToObject can wrap almost any value in an object wrapper — a number, a string, a boolean — but the spec explicitly makes null and undefined the two exceptions that throw a TypeError instead. Contrast this with object spread ({...value}), which the spec defines to silently skip a null/undefined source and produce an empty object — a deliberate difference, not an inconsistency, so switching between spread and Object.keys isn't purely stylistic.
What does and doesn't throw
| Expression | With null/undefined |
|---|---|
Object.keys(x) / values(x) / entries(x) | ❌ throws |
Object.assign(x, ...) — x is the target | ❌ throws |
Object.assign({}, x, ...) — x is a source | ✅ skipped, no-op |
{...x} (object spread) | ✅ produces {} |
for (const k in x) | ✅ iterates zero times |
✓ Confirm it's fixed
- Run the code path against a record where the field is genuinely
null— no throw, empty result instead. Object.assigncalls always have a literal{}(or guaranteed object) as the target, never a variable that could be empty.- Search the codebase for other
Object.keys/values/entries(calls on the same field and apply the same default.
Frequently Asked Questions
What does 'Cannot convert undefined or null to object' mean?
You called an Object static method — Object.keys, Object.values, Object.entries, or Object.assign with null/undefined as the target — and that method internally tries to coerce its argument to an object first. null and undefined are the only two values JavaScript refuses to coerce this way, so the coercion step itself throws before your method logic ever runs.
Why doesn't object spread have this problem?
Object spread ({...value}) is defined to silently treat a null/undefined source as contributing no properties, producing an empty object instead of throwing. This is a deliberate spec difference — spread is forgiving, Object.keys/values/entries/assign are not — so switching between the two isn't just a style choice.
Why does this show up after fetching API data?
A field that's usually an object can come back as null for some records — a user with no profile, a cancelled order with no shipping info — and calling Object.keys(response.data.profile) blows up only for those records. It often passes testing because your sample data happened not to include the empty case.
Does Object.assign always throw with null/undefined?
Only when null/undefined is the target (the first argument) — that's what gets coerced to the object being built. Object.assign({}, null, {a: 1}) does NOT throw: null and undefined as sources are simply skipped, contributing nothing, same as spread.
What about for...in on a null value?
for (const k in null) also does not throw — it silently iterates zero times, same as an empty object would. The Object static methods (keys/values/entries) and Object.assign's target position are the specific cases that throw; most other "read from a possibly-empty object" operations in JS are forgiving.
How do I make this stop happening entirely?
Default the value before calling an Object method: Object.keys(value ?? {}) always works, whether value is an object, null, or undefined. Doing this at every call site (or once at the point the value enters your code) removes the failure mode permanently rather than fixing it one crash at a time.
More JavaScript & runtime errors
Browse the full reference for JavaScript, Node.js, and database errors — exact message, cause, and fix.