A null-assignment TypeError means the object on the left side of a write did not exist at that moment. DOM lookup, component lifetime, async races, and nullable domain state each require a different repair.
Make required targets assertive, optional targets explicit, object construction schema-aware, and delayed updates ownership-aware. Do not replace meaningful null states with empty objects merely to suppress the exception.
The error TypeError: Cannot set property 'x' of null occurs when you try to assign a value to a property of a variable that is null. This is similar to the "cannot read property" error but happens during assignment.
// [wrong] Problem
let user = null;
user.name = 'John'; // TypeError!
// [ok] Solution 1: Check if exists
if (user) {
user.name = 'John';
}
// [ok] Solution 2: Initialize object first
let user = {};
user.name = 'John'; // Works!
// [ok] Solution 3: Optional chaining with nullish coalescing
user = user ?? {};
user.name = 'John';
// Element doesn't exist in HTML
const input = document.querySelector('#username');
input.value = 'John'; // TypeError: Cannot set property 'value' of null
// Typo in selector
const button = document.querySelector('#sumbit-btn'); // typo: sumbit
button.disabled = true; // TypeError!
// Solution 1: Check if element exists
const input = document.querySelector('#username');
if (input) {
input.value = 'John';
} else {
console.error('Input element not found');
}
// Solution 2: Use optional chaining (modern browsers)
const button = document.querySelector('#submit-btn');
if (button) button.disabled = true;
// Solution 3: Wait for DOM to load
document.addEventListener('DOMContentLoaded', () => {
const input = document.querySelector('#username');
if (input) input.value = 'John';
});
let user = null;
user.name = 'John'; // TypeError!
// Or from function return
function getUser() {
return null; // User not found
}
const user = getUser();
user.email = 'john@example.com'; // TypeError!
// Solution 1: Initialize before use
let user = {}; // Initialize as empty object
user.name = 'John'; // Works!
// Solution 2: Check before setting
let user = null;
if (user === null) {
user = {};
}
user.name = 'John';
// Solution 3: Use nullish coalescing
let user = null;
user = user ?? {}; // If null, use empty object
user.name = 'John';
// Solution 4: Handle in function
function getUser() {
return null;
}
const user = getUser() || {}; // Default to empty object
user.email = 'john@example.com'; // Safe now
let data = {
user: null
};
data.user.name = 'John'; // TypeError: Cannot set property 'name' of null
// Or with API response
const response = {
data: null
};
response.data.items = []; // TypeError!
// Solution 1: Initialize nested object
let data = {
user: {} // Initialize as empty object
};
data.user.name = 'John'; // Works!
// Solution 2: Check before setting
let data = {
user: null
};
if (!data.user) {
data.user = {};
}
data.user.name = 'John';
// Solution 3: Use nullish coalescing
let data = {
user: null
};
data.user = data.user ?? {};
data.user.name = 'John';
// Solution 4: Safe assignment function
function safeSet(obj, path, value) {
const keys = path.split('.');
let current = obj;
for (let i = 0; i < keys.length - 1; i++) {
if (!current[keys[i]]) {
current[keys[i]] = {};
}
current = current[keys[i]];
}
current[keys[keys.length - 1]] = value;
}
let data = { user: null };
safeSet(data, 'user.name', 'John'); // Safe!
<!DOCTYPE html>
<html>
<head>
<script>
// Runs before body is parsed
const input = document.querySelector('#username');
input.value = 'John'; // TypeError: input is null
</script>
</head>
<body>
<input id="username" type="text">
</body>
</html>
<!-- Solution 1: Move script to end of body -->
<body>
<input id="username" type="text">
<script>
const input = document.querySelector('#username');
input.value = 'John'; // Works!
</script>
</body>
<!-- Solution 2: Use DOMContentLoaded -->
<head>
<script>
document.addEventListener('DOMContentLoaded', () => {
const input = document.querySelector('#username');
if (input) input.value = 'John';
});
</script>
</head>
<!-- Solution 3: Use defer attribute -->
<head>
<script defer src="app.js"></script>
</head>
A null-assignment TypeError means JavaScript evaluated the object reference on the left side and obtained `null` before it could write the property. In `panel.querySelector("button").disabled = true`, the missing value is the selector result, not `disabled`. Break the chain and inspect the lookup result at the first uncertain boundary.
`null` commonly represents an intentional absence, while `undefined` often comes from a missing property or omitted return, but JavaScript does not enforce those meanings. Both are nullish and neither can receive a property. Define what each function may return instead of choosing a repair from the wording alone.
Optional chaining cannot be used as an assignment target. An expression such as `element?.textContent = value` is invalid syntax because silently skipping a required write would hide whether the update happened. Branch explicitly when absence is expected, or assert and fail clearly when the element or object is required.
The correct repair depends on ownership. A missing optional target can be skipped, a required target should produce an invariant error, a not-yet-created target requires lifecycle coordination, and a nullable domain record may require a user-visible not-found path. Replacing every null with `{}` can create invalid state.
`querySelector` returns the first matching element or `null`; `getElementById` also returns `null` when no element has that ID. A failed lookup can mean a selector typo, wrong document or shadow root, conditional markup, an element already removed, or code running before that part of the document exists.
A deferred classic script and a module script run after document parsing by default, before `DOMContentLoaded`. A script placed after its markup can also query it directly. Waiting for `DOMContentLoaded` is useful when initialization may run earlier, but it cannot repair a selector that never matches or content that is created later.
For dynamically mounted interfaces, initialize from the component lifecycle or observe the actual insertion boundary. Keep the element reference only while its owner is mounted, and verify `isConnected` when delayed work may outlive it. A stale detached element can accept property writes while producing no visible update.
Create a small required-element helper that accepts a root and selector, validates the expected element type, and throws a message containing component and selector context in development. For optional enhancement, use an explicit nullable lookup and return without mutating. This makes required and optional markup contracts visible.
Initialize an object only when object creation is a valid transition. If `currentUser` is null because no one is authenticated, assigning `{}` and then setting `currentUser.role` invents a user and can bypass important checks. Construct a complete valid value through a factory or leave the state absent.
Nullish assignment, `value ??= fallback`, assigns only when the current value is null or undefined. It preserves valid falsy values, but it still mutates the containing binding and does not validate the fallback. Use it for lazy caches or optional containers whose creation rule is already established, not as a universal error suppressor.
For nested data, create each missing container according to a schema. A generic path setter cannot know whether a segment should be an object, array, map, or forbidden field, and unsafe keys can cause prototype-related security problems. Prefer a domain-specific update that names the allowed path and validates its value.
Immutable state updates must also handle absence. Read the current variant, reject or construct a valid next variant, then copy only the owned levels. Spreading `null` may produce behavior that obscures the missing state, and a shallow copy does not protect nested objects from accidental mutation.
A reference that existed before an `await` may be cleared, replaced, or made obsolete before execution resumes. Capture an operation identity, then re-read and validate current state before the write. This matters for dialogs, selected records, routes, editor documents, and any state invalidated by navigation or cancellation.
Two updates can race even on a single JavaScript thread because asynchronous jobs interleave. A late response may attempt to write into state that a newer request reset to null. Abort obsolete work when possible and compare request versions before committing. Do not recreate cleared state from a stale response.
DOM event handlers may run after teardown if listeners or timers were not cleaned up. Tie listeners, fetches, observers, and scheduled work to one abortable component lifecycle. Teardown should mark the owner inactive before releasing resources so callbacks already queued can reject the write.
Server mutations need their own concurrency controls. A client-side null guard cannot prevent lost updates or writes to deleted records. Send record identity and version where the API supports optimistic concurrency, handle conflict and not-found responses, and refresh state deliberately instead of applying a stale local patch.
Pause on exceptions and inspect the left-hand object, selector root, lifecycle state, and preceding async boundary. Set a DOM mutation breakpoint when another operation removes the target unexpectedly. For application objects, watch the assignment that first changes the reference to null, not only the later failing write.
Log the stable component name, selector or record ID, lifecycle phase, request version, and release. Avoid logging form values, access tokens, or full records. If the error appears only in production, verify that source maps match the deployed bundle and that server-rendered or feature-flagged markup matches the client release.
Test missing required markup, absent optional markup, initialization before and after parsing, component teardown before a delayed callback, a stale request, and a domain object intentionally set to null. Assert whether the contract throws, skips, constructs, or reports not found; merely asserting that no TypeError appears is too weak.
Static types can require a null check, but DOM selectors and external state still need runtime assertions. Use strict null checking, narrow values close to lookup boundaries, and avoid non-null assertions unless another invariant is both documented and tested. An assertion operator removes a compiler warning; it does not create the object at runtime.
Try this next
0 of 2 completed
This error occurs when you try to assign a value to a property of a variable that is null. Common causes include DOM elements not found, uninitialized objects, or scripts running before DOM is ready.
First decide whether the target is required, optional, not yet created, or intentionally absent. Assert a required target, branch for an optional target, or construct a complete valid object; optional chaining cannot be used on the left side of an assignment.
querySelector returns null when no element matches the selector. Common reasons: typo in selector, element doesn't exist in HTML, or script runs before DOM is loaded.
Explore 500+ free tutorials across 20+ languages and frameworks.