Lighthouse audit errors-in-console · Best Practices

"Browser errors were logged to the console": how to fix it

View raw .md for LLMs / your notes
Quick answer: This audit fails when anything the page loads writes an error to the browser console, including failed network requests and uncaught JavaScript exceptions. Read the exact messages in the Lighthouse report, then fix them at the source: broken asset URLs, scripts running before the DOM exists, CORS and CSP blocks, and third-party tags you can defer or delete.

This audit fails when anything on your page writes an error to the browser console while it loads. It is one of the most commonly failed audits in the wild: in our study of 269 Shopify storefronts, 243 of them (90.3%) failed it. It is also one of the easiest to fix, because Lighthouse hands you the exact error text.

TL;DR

What does "browser errors were logged to the console" mean?

Lighthouse listens to the console for the whole page load and collects every entry at error level. Two different things end up in that bucket:

The audit passes only when the count is zero. There is no threshold and no partial credit, which is why a single stale image URL fails it.

What does this audit ignore?

Knowing what does not count saves time:

So the audit is narrower than the console tab looks when you browse the site by hand. If DevTools shows twenty red lines and Lighthouse reports two, the other eighteen fired after load.

How do I find which console errors Lighthouse flagged?

The report gives you the source URL and the full message, so you rarely need to guess:

  1. In the Lighthouse report, open Best Practices and expand "Browser errors were logged to the console". Each row has the source (the file and line, or the request URL) and the error text.
  2. In the JSON output, the same rows are machine-readable, which is the fastest path when you are fixing several pages at once:

   lighthouse https://example.com --output=json --quiet \
     | jq -r '.audits["errors-in-console"].details.items[]
              | [.source, (.description // .sourceLocation.url)] | @tsv'
   

  1. In DevTools, reproduce the load properly. Open the console, tick Preserve log, hard-reload, and read from the top. Errors during load scroll away fast otherwise.

Two settings matter when you reproduce by hand: use an incognito window or a clean profile, because extensions inject their own errors, and disable the cache, because a 404 on a cached asset will not repeat until the cache clears.

What are the most common console errors and how do I fix each?

Failed to load resource: the server responded with a status of 404 ()

The most frequent cause by a wide margin, and always a real bug. Usual sources: an asset renamed or deleted while a template still points at the old path, a hard-coded absolute URL that is right on staging and wrong in production, a hashed filename left over from a previous build, or a case mismatch (Logo.png versus logo.png, which works on macOS and fails on Linux hosts).

Fix the reference or restore the file. If the asset is genuinely gone, remove the tag that requests it rather than leaving a 404 in the load path.

Uncaught TypeError: Cannot read properties of null (reading '...')

A script ran before the element it wanted existed. Classic causes are a <script> in the <head> without defer, or code that assumes an element rendered by a later component.

// Fails when the script runs before the element parses
document.querySelector('#banner').classList.add('ready');

// Guard, and let the parser finish first
const banner = document.querySelector('#banner');
if (banner) banner.classList.add('ready');

Add defer to the script tag, or move the work into a DOMContentLoaded handler. The guard stops the exception; the defer fixes the ordering that caused it.

Uncaught ReferenceError: <name> is not defined

A dependency has not loaded yet, usually because a library tag sits below the code that calls it, or an async library is being used by a synchronous script. Load order is the fix: defer preserves relative order between scripts, async does not.

Access to fetch at '...' has been blocked by CORS policy

The browser blocked a cross-origin request because the response lacked the right Access-Control-Allow-Origin header. This is a server-side fix on the API being called, not something you can patch from the page. If you do not control that server, proxy the request through your own backend.

Mixed Content: The page at 'https://...' was loaded over HTTPS, but requested an insecure resource

An http:// URL on an https:// page. Modern browsers block it and log an error. Change the reference to https://, or to a protocol-relative path if the host supports both. See Does not use HTTPS for the full picture, since the same root cause fails that audit too.

Refused to execute inline script because it violates the following Content Security Policy directive

Your CSP is stricter than your markup. Either move the inline script into a file, or add a nonce or hash for it. Loosening the policy to unsafe-inline clears the error and costs you the protection the header was there for, so treat that as a last resort.

net::ERR_NAME_NOT_RESOLVED or a request that never completes

A third-party domain that no longer exists, usually an analytics or widget vendor that shut down or a tag left behind after a migration. Delete the tag. It is pure cost: a DNS lookup, a console error, and no feature.

How do I fix console errors from third-party scripts?

You often cannot fix the script itself, so you have three real options, in order of preference:

  1. Remove it. Audit what the tag actually does. Abandoned analytics, duplicate pixels, and A/B tools nobody uses anymore are common and safe to drop. This also helps Reduce unused JavaScript.
  2. Load it later. Moving a non-critical tag to after load, ideally inside requestIdleCallback, keeps it off the critical path. It may still throw, so this alone does not always clear the audit.
  3. Report it to the vendor and pin a version. If the tag is load-bearing, a version pin at least keeps a working build in place while they fix it.

What not to do: wrap the vendor's code in an empty catch, or override console.error. Both hide the symptom from Lighthouse and from you, and neither makes the broken feature work.

How do I verify the fix?

  1. Re-run Lighthouse. "Browser errors were logged to the console" should move into the passed-audits list.
  2. Load the page in a clean profile with Preserve log enabled and confirm the console is empty through the whole load.
  3. Check a second page type. Console errors are usually template-level, so a product page and a cart page can each carry their own.
  4. If you fixed a 404, confirm the asset returns 200 with curl -sSI <url> rather than trusting a cached page.

What mistakes should I avoid?

Related audits


Audit your URL at https://lighthouse-md.com.

Audit your page now

Paste your URL, get scores plus a CLAUDE.md plan for Claude Code.

Run audit →