Skip to content

Cannot read properties of null

Your code read a property from null. Unlike undefined, null is almost always returned on purpose, by a DOM query, a ref, storage, or an API field.

Updated September 24, 2026 by the Squasher team

What the error means

In TypeError: Cannot read properties of null (reading 'addEventListener'), the value to the left of .addEventListener was null. The code expected an object and got nothing.

Browser APIs return null when there is no result: getElementById and querySelector with no match, closest() with no ancestor, match() with no match, and localStorage.getItem() for a missing key. JSON can carry null but never undefined, so API fields fail this way too.

The error message in each browser or library
WhereMessage
Chrome, Edge, Node.jsTypeError: Cannot read properties of null (reading 'addEventListener')
FirefoxTypeError: can't access property "addEventListener", button is null
SafariTypeError: null is not an object (evaluating 'button.addEventListener')

Common causes

  • document.getElementById() or querySelector() matched nothing: a typo in the selector, or the element is on another page.
  • The script runs before the element exists, for example a classic script in the head without defer.
  • A React ref is read during render, before mount, or after unmount, when ref.current is null.
  • A regular expression did not match: "abc".match(/\d+/) returns null, so match[0] fails.
  • The API returned null for a field or relation that the UI treats as always present.

Reproduce it

Query an element before it is in the DOM, then use the result.

TypeScript
// Runs before <button id="save"> is parsedconst button = document.getElementById("save"); // nullbutton.addEventListener("click", saveDraft);// TypeError: Cannot read properties of null (reading 'addEventListener')

Fix it

  1. Run DOM code after the element exists

    Load the script with defer or type="module", or wait for DOMContentLoaded. Then check the result, because the element may not be on every page.

    TypeScript
    document.addEventListener("DOMContentLoaded", () => {  const button = document.getElementById("save");  if (!button) return; // this page has no save button  button.addEventListener("click", saveDraft);});
  2. Read React refs in effects and handlers

    React sets ref.current after the element mounts and clears it on unmount. Read it in useEffect or an event handler, never during render.

    TypeScript
    const inputRef = useRef<HTMLInputElement>(null); useEffect(() => {  inputRef.current?.focus(); // set after mount}, []);
  3. Check results that can be null

    Treat match(), getItem(), and closest() as maybe-null, and choose a fallback before you use the value.

    TypeScript
    const match = orderRef.match(/\d+/);const orderId = match ? Number(match[0]) : null; const saved = localStorage.getItem("draft");const draft = saved ? JSON.parse(saved) : { title: "" };

Catch it in production

The Squasher browser SDK sends this error to your project when it happens, so you do not wait for a user to report it.

  • Uncaught errors are captured with the stack frames, page URL, release, and session ID.
  • Session replay is on by default in the browser SDK, and replays share the session ID with errors, so you can see whether the element was on screen.
  • Call setTag with the page or feature name, so each event says where the element was missing.
src/editor.ts
import { init, setTag } from "@squasher-ai/browser"; init({  apiKey: import.meta.env.VITE_SQUASHER_API_KEY,  projectId: import.meta.env.VITE_SQUASHER_PROJECT_ID,  release: import.meta.env.VITE_GIT_SHA,  replay: { enabled: true, sampleRate: 0.1 },}); setTag("page", "editor");
app.squasher.ai/acme/editor-web/issues

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

TypeError

MediumUnresolvedError
Events
86
First seen
1d ago
Last seen
12m ago
Environment
production
Service
editor-web

Example code and issue.

JavaScript error monitoring with Squasher

Catch the next one first.

Send browser errors to Squasher and fix them before the support ticket arrives.

Free plan. No credit card required.