Fixing JavaScript Console Errors at Page Load
A red line in the browser console usually means something on the page did not run. Visitors never see the message itself; they see a menu that will not open, a basket that stays empty or a form that does nothing when they press send. Some console messages are harmless, others break a sale.
This guide shows you how to capture the errors a page throws while it loads, decide which ones are yours to fix, trace a minified message back to the real line of code, and fix the handful of error types that cause almost every problem.
How to read a console error
Every uncaught error in the console has the same four parts, and each one narrows down where to look.
- The type.
TypeError,ReferenceError,SyntaxErrorandRangeErrorare thrown by the JavaScript engine itself. A message beginningUncaught (in promise)is a rejected promise that nothing handled. Network, CORS, Content Security Policy and mixed-content messages come from the browser rather than from your code. - The message. The wording varies between browsers. Chrome says
Cannot read properties of null (reading 'addEventListener'); Firefox sayscan't access property "addEventListener", el is null. Both mean the same thing: the code expected an element or object and got nothing. - The location. The link on the right of the message names the file, line and column.
On a live site that is often a minified bundle such as
app.3f9c1.js:1:48213, which is where source maps come in. - The stack trace. Expand the message to see the chain of function calls that led to the error. The top frame is where it failed; the frames below show who called it, which is often where the real mistake is.
An uncaught error ends the task it happened in. Code later in the same function, and anything that function was supposed to set up, never runs. Other scripts, and other tasks in the same script, carry on. That is why one error can break the mobile menu while the rest of the page looks fine.
The errors you will meet most often
| Message (Chrome wording) | What it really means | Usual cause |
|---|---|---|
Cannot read properties of null (reading 'x') | A lookup such as querySelector
found nothing, then the code used the result. | The element is missing on this template, was renamed, or the script ran before the HTML existed. |
Cannot read properties of undefined (reading 'x') | An object or array entry the code expected is absent. | An API response with a missing field, an empty list, or a setting that was never passed in. |
x is not a function | The name exists but holds something else, or a method is missing. | Two versions of a library, a plugin that expects jQuery methods that are not loaded, or a typo in a method name. |
x is not defined (ReferenceError) | No variable of that name exists when the line runs. | A library loaded later than the code using it, or a script that was removed while code still calls it. |
Uncaught (in promise) | An asynchronous operation failed and nothing caught it. | A fetch that got a 404 or 500 and was then parsed as JSON, or an await
with no error handling. |
Failed to load resource: 404 | A file the page asked for does not exist. | A renamed bundle after a deploy, an old theme path or a cached HTML page pointing at deleted files. |
Script error. | An error inside a script from another origin, with the details hidden. | A third-party or CDN script loaded without CORS headers and the crossorigin
attribute. |
Refused to load the script ... Content Security Policy | Your own security header blocked it. | A new tag or CDN domain that was never added to the policy. |
Mixed Content: ... requested an insecure script | An https page tried to load an http script, and the browser blocked it. | A hard-coded http address in a theme setting or pasted snippet. |
Warnings in yellow, such as deprecation notices or messages about third-party cookies, are worth reading but rarely stop anything working. Treat red errors first.
Sorting the noise: who owns each error
A busy page can log dozens of messages. Before fixing anything, work out who can actually change the code that failed. The file address in each message usually tells you.
- Your own code. Files served from your domain or your own CDN that your team or agency writes. Fix these.
- Your platform, theme or plugins. Files under paths such as
/wp-content/plugins/, a Shopify theme'sassetsfolder or an installed app. You can often fix these by updating, reconfiguring or replacing the component, but editing vendor files directly is usually overwritten by the next update. - Third-party tags. Analytics, chat, reviews, advertising and consent scripts from other domains. You cannot fix their code; you can fix how you load and configure them, report the bug, or remove them.
- Not the page at all. Messages from
chrome-extension://ormoz-extension://addresses come from the tester's browser add-ons. Ad blockers also cause failed requests to tracking domains. Your visitors with different set-ups will not see these, so ignore them.
To be sure a message is real, reproduce it in a private window or a fresh browser profile with no extensions. The JavaScript Checker loads the page in headless Chromium without add-ons, so the errors it captures are the ones the page itself produces.
Getting from a minified bundle to the real line
Production code is bundled and minified, so an error at main.8a1d.js:1:90412 tells you
very little. A source map is a separate file, produced by your build tool, that lets developer tools
translate that position back to the original file, line and variable names.
- Vite: set
build.sourcemaptotrueor'hidden'in the config. - webpack: set
devtoolto'source-map'or'hidden-source-map'for production builds. - esbuild: pass
--sourcemap, or--sourcemap=externalto write the map without linking to it. - Next.js: set
productionBrowserSourceMapsto true in the Next config if you want maps served publicly.
With a public map, Chrome and Firefox show the original file straight away in the Sources or Debugger panel. With a hidden map, the bundle does not link to it, so visitors cannot fetch your source, but you can still load the map yourself: in Chrome, right-click in the bundle in the Sources panel and add the source map by address, or upload the maps to your error monitoring service so its stack traces are readable.
// A stack frame before and after mapping
at e.init (main.8a1d.js:1:90412)
at initBasket (src/basket/drawer.js:42:17)
The fix, step by step
Step 1
Capture the console on a clean browser profile
Run the page through the JavaScript Checker to get the console errors and warnings it captures during load, then open the same address in a private window with extensions off. In developer tools, open the Console, tick Preserve log so messages survive redirects, and reload. Repeat on each key template: home, category, product, basket, checkout and contact. Copy each error with its file and line into a simple list.
Step 2
Sort every message by who owns it
Read the file address beside each error and put it in one of four groups: your own code, your theme or plugins, third-party tags, or browser extensions. Delete the extension messages from the list. Then mark which errors stop something a visitor needs, such as navigation, search, basket or forms, by testing that feature by hand. Those go to the top of the list whoever owns them.
Step 3
Map minified errors back to source
Turn
on source maps in your build, using hidden maps if you do not want your source public, and
deploy or load them locally. Click the file link in the error to jump to the original line in the Sources
panel, then expand the stack trace. The top frame shows where it failed; read down the frames to find
the caller that passed in the empty or wrong value.
Step 4
Fix null and undefined TypeErrors
Find
the lookup that returned nothing. If the element is simply absent on some templates, check for it and
return early before attaching listeners. If it should exist, fix the selector or the template. For data,
use optional chaining such as data?.items?.length with a sensible default, and validate
API responses before using them. Do not wrap the whole file in try and catch to hide the message.
Step 5
Fix ReferenceErrors caused by load order
When a name is not defined, check whether the library that provides it is loaded later,
loaded with async, or removed. Give dependent scripts defer so they run in
order, move inline code that calls a library into a deferred file or a DOMContentLoaded
listener, and remove calls to tools you no longer load. Make sure the library is included only once,
in one version.
Step 6
Handle rejected promises and failed requests
Check response.ok before parsing any fetch result, wrap each
await chain in try and catch, and show visitors a clear fallback message when a request
fails. Look in the Network panel for the request behind each rejection: a 404 means the endpoint moved,
a 401 or 403 means a missing token or cookie, and a 500 needs fixing on the server rather than in the
browser.
Step 7
Clear missing-file, CORS and CSP errors
For 404s on script files, purge page and CDN caches after each deploy so old HTML stops
asking for deleted bundles, and fix any hard-coded paths. For Script error. from your own
CDN, send an Access-Control-Allow-Origin header and add crossorigin to the
tag. For CSP blocks, add the exact domain the tag needs to the policy rather than loosening it with a
wildcard.
Step 8
Watch real-visitor errors after release
Re-run the checker on every template you changed and confirm the red errors have gone.
Then add error monitoring to the live site, either a hosted service or a small listener for error
and unhandledrejection events that posts to your server, and upload source maps with each
release. Real browsers, journeys and connections will surface errors that a single test load never triggers.
Code patterns that stop the common errors
Only wire up features that exist on this page
Sites often load one bundle on every template. Code for a product gallery then runs on the contact page and throws because there is no gallery. Check first and leave quietly.
const gallery = document.querySelector('[data-gallery]');
if (gallery) {
gallery.addEventListener('click', openLightbox);
}
Trust nothing that comes back from a request
async function loadStock(sku) {
try {
const res = await fetch(`/api/stock/${encodeURIComponent(sku)}`);
if (!res.ok) throw new Error(`Stock lookup failed: ${res.status}`);
const data = await res.json();
return data?.available ?? 0;
} catch (err) {
console.warn(err);
return null; // the caller shows "Check availability in store"
}
}
A very common rejection reads Unexpected token '<' inside a promise. It means the
server returned an HTML error page and the code tried to parse it as JSON. Checking res.ok
first turns a confusing parse error into a clear status code.
Wait for the library, not for luck
<script src="/js/vendor/slider.min.js" defer></script>
<script src="/js/home.js" defer></script>
<!-- home.js can safely call Slider() because deferred scripts run in order -->
A minimal error listener
window.addEventListener('error', (e) => {
navigator.sendBeacon('/log/js', JSON.stringify({
msg: e.message, src: e.filename, line: e.lineno, col: e.colno, page: location.pathname
}));
});
window.addEventListener('unhandledrejection', (e) => {
navigator.sendBeacon('/log/js', JSON.stringify({
msg: String(e.reason), page: location.pathname
}));
});
This is enough to learn which errors real visitors hit and on which pages. A hosted monitoring service adds grouping, source-map support and alerts, which becomes worth it once traffic grows.
Platform notes
WordPress
Most console errors on WordPress sites come from plugins and themes rather than from WordPress itself.
Performance plugins that combine or delay scripts are a frequent cause of jQuery is not defined
and $ is not a function, because they change the order scripts run in. Switch the delay
or combine option off to confirm, then exclude the affected file. The Health Check and Troubleshooting
plugin lets you disable plugins for your own session only, so you can find the culprit without taking
the live site down.
Shopify
Errors often come from app embeds and from snippets left behind when an app was uninstalled. Search the theme code for the missing name in the error, check App embeds in the theme editor, and test with a duplicate of the theme before changing the live one.
Custom sites and frameworks
Here the errors are yours, so source maps and a test for each fixed bug pay off quickly. Add a check to your end-to-end tests that fails the build when the console logs an error on key pages; tools such as Playwright can listen to console events during a test run.
Edge cases that waste time
- The error only happens once. Errors that appear on first visit but not on reload are often about caching or consent: a script that expects a cookie, or code that runs before the consent banner has recorded a choice. Test in a new private window every time.
- The error only happens on phones. Mobile templates may hide or remove elements that desktop code expects, and older mobile browsers may lack a newer method. Use device mode and, better, a real phone with remote debugging.
- The message is just
Script error.Browsers hide the details of errors in cross-origin scripts. You need both thecrossoriginattribute on the tag and a CORS header from the server that hosts the file before the real message and line appear. - Errors in the checker but not in your browser. A headless browser starts with no cookies, no saved consent and a set window size. That is closer to a first-time visitor than your own browser, so take these errors seriously.
- Swallowed errors. A
catchblock that does nothing hides the error from the console and from monitoring. At minimum, log it.
Keeping the console clean
- Fail the build on console errors. Run end-to-end tests on your main journeys and treat any logged error as a failed test.
- Keep source maps for every release and upload them to your monitoring service automatically.
- Review every new tag. Before a new third-party script goes live, load a test page with it and check the console and the Content Security Policy.
- Purge caches on deploy. Most post-release 404s on script files come from cached HTML pointing at bundles that no longer exist.
- Re-check key templates regularly. Plugin, app and vendor updates change code without anyone on your team touching it.
1. Do JavaScript console errors hurt my Google rankings?
Search engines do not read your console or score a page on how many errors it logs. The risk comes from what the error stops. If a script that builds product details, internal links or structured data fails when Google renders the page, that content may be missing from what gets indexed. If the error breaks a form or basket, visitors leave. Judge each error by the feature it breaks rather than by the number of red lines.
2. What does Cannot read properties of null mean?
The code asked the page for something, usually an element found with querySelector or getElementById, got nothing back, and then tried to use it anyway. It usually happens because the element does not exist on that template, its class or ID was renamed, or the script ran before the HTML had been parsed. Check for the element before using it, fix the selector, or load the script with defer so it runs after the page structure exists.
3. Why does the console only say Script error with no details?
Browsers hide the details of errors that happen inside scripts loaded from another origin, to stop one site learning about another. To see the real message and line, the script tag needs the crossorigin attribute and the server hosting the file must send an Access-Control-Allow-Origin header that permits your site. You can set both for files on your own CDN. For third-party vendors you depend on them supporting it, which many large providers do.
4. Should I fix errors caused by third-party scripts?
You cannot edit their code, but you can often remove the cause. Many third-party errors come from a wrong account ID, a missing container element, a consent state the script did not expect, or loading it twice through a tag manager and the theme. Check your set-up first. If the error is genuinely in the vendor's code, report it with the page address and browser, and decide whether the tag is worth keeping if it keeps breaking.
5. Why do I see errors that my visitors probably do not?
Browser extensions inject their own scripts into every page, and their errors appear in your console with chrome-extension or moz-extension addresses. Ad blockers also cause failed requests to analytics and advertising domains. Neither says anything about your site. Test in a private window or a new browser profile with extensions switched off, or rely on the JavaScript Checker's headless browser, which loads the page without add-ons, to see only the errors the page itself causes.
6. Is it safe to wrap everything in try and catch?
Only in the places where you know what to do when something fails, such as a network request that can show a fallback message. Wrapping a whole file in try and catch hides the error without fixing it, and a catch block that does nothing also hides the problem from your error monitoring. Fix the cause of the error, check for missing elements and data before using them, and keep try and catch for operations that can genuinely fail.
7. How do I find the error in minified code?
Enable source maps in your build tool, for example build.sourcemap in Vite or devtool in webpack. Developer tools then translate the minified file and column into the original file, line and names. If you do not want the maps public, create hidden maps that the bundle does not link to, load them into developer tools yourself when debugging, and upload them to your error monitoring service so live stack traces are readable.
8. How often should I check for console errors?
After every deploy, after plugin, theme or app updates, and whenever a new third-party tag is added, because each of these can change the code on the page without anyone noticing. Between those events, error monitoring on the live site does the watching for you, and a regular run of the JavaScript Checker on your key templates catches errors on pages that get too little traffic to show up in monitoring quickly.
The JavaScript Checker loads your page in headless Chromium and captures console errors and warnings, alongside bundle size, parse and execution time, render-blocking scripts and third-party tags.
Open JavaScript Checker Fixes โ