Reading Errors from the Extensions Page

Use the Errors view on chrome://extensions to find MV3 failures you never saw — manifest warnings, uncaught errors from every context, stack traces with context, and clearing noise.

Published September 18, 2026 Updated September 18, 2026 7 min read
Table of Contents

When an extension fails without anyone watching — the worker threw during a cold start, a content script hit an exception on a site you have never visited, a manifest key was ignored — the evidence usually still exists. Chrome collects uncaught errors from every extension context into one place, the Errors button on chrome://extensions, with the context, the file and line, and the stack. It is the closest thing an extension has to a crash log, and it is visible only in Developer mode, which is why so few people look at it. This guide is part of debugging extension contexts.

What the Errors view collects

What reaches the Errors viewManifest warnings, uncaught exceptions, unhandled promise rejections, console.error calls and caught errors compared on whether they appear in the Errors view and from which contexts.KindAppearsFrom which contextsManifest warningsYesInstall / reloadUncaught exceptionsYesWorker, pages, content scriptsUnhandled rejectionsYesWorker, pagesconsole.error()Yes, as errorsWorker, pagesCaught and swallowedNo
Caught errors are invisible here — which is why logging them yourself still matters.

Step-by-step

1. Turn on Developer mode and open the view

On chrome://extensions, toggle Developer mode (top right). An Errors button appears on each extension’s card when it has recorded at least one error. Clicking it opens a list, newest first.

Each entry shows the message, the context it came from (the worker, a page URL, or a content script on a specific site), a timestamp, and a stack trace whose frames link into the source.

2. Read the context before the message

The same message means different things in different contexts. “Cannot read properties of null” in the worker is a logic bug; in a content script on one website it is a site-specific DOM assumption; in the popup it may be a race with rendering.

1Uncaught TypeError: Cannot read properties of null (reading 'textContent')
2Context: https://news.example.com/article/4821
3Stack Trace:
4  content/main.js:88 (anonymous function)

Execution context: this is how a content-script error is shown — the “Context” line is the page URL, which immediately tells you the failure is site-specific. The same error with Context: sw.js would be in the worker.

3. Make your own errors show up with useful stacks

Errors thrown from minified bundles show minified stacks. Ship readable output to development builds and upload source maps separately for release — Chrome does not fetch maps for the Errors view.

1// vite.config.js
2export default {
3  build: {
4    minify: process.env.NODE_ENV === "production",
5    sourcemap: process.env.NODE_ENV === "production" ? "hidden" : true,
6  },
7};

Execution context: the build. In development builds the stack in the Errors view points at real function names and lines; in release builds you rely on your own reporting to symbolicate, as described in wiring Sentry into a Manifest V3 extension.

4. Turn silent failures into recorded ones

Caught errors never reach the view. An error swallowed by catch {} or by a promise chain without a rejection handler is invisible here and everywhere else.

1// Invisible:
2chrome.tabs.sendMessage(tabId, msg).catch(() => {});
3
4// Visible, and still non-fatal:
5chrome.tabs.sendMessage(tabId, msg).catch((err) => {
6  if (!/Receiving end does not exist/.test(err.message)) console.error("[sw] sendMessage failed", err);
7});

Execution context: the service worker. Ignoring the one expected rejection — no content script in the tab — and logging everything else with console.error puts genuine failures into the Errors view without flooding it. The expected case is covered in fixing “message port closed before response” errors.

5. Clear, reproduce, read

The view accumulates entries until cleared, and stale errors from a previous build are a common source of confusion. Clear it, reproduce the problem, and read only what the current build produced.

11. chrome://extensions → Errors → Clear all
22. Reload the extension (the circular arrow on its card)
33. Reproduce the issue with DevTools closed
44. Reopen Errors — everything listed is from this build and this run

Execution context: the browser’s extension management UI. Reproducing with DevTools closed matters because an attached inspector keeps the worker alive and hides lifecycle errors, as described in finding the right DevTools target for each context.

6. Check the manifest warnings at the top

Warnings about the manifest appear at the top of the card, not in the Errors list: unknown keys, unrecognised permissions, deprecated fields. They are easy to miss and occasionally explain a feature that silently does nothing.

1Unrecognized manifest key 'browser_specific_settings'.
2Permission 'offscreen' is unknown or URL pattern is malformed.

Execution context: shown on the extension card after install or reload. The first line is harmless in a shared manifest; the second, in a Chrome build, means the Chrome version is too old for the API — and chrome.offscreen will be undefined at runtime. Generating per-target manifests, as in generating a manifest per browser target, removes both.

Using the Errors view as a crash logClear old entries, reload the extension, reproduce with inspectors closed, then read entries by context and follow stack frames into the source.Clear allold builds goneReload extensionfresh workerReproduce, DevTools closedreal lifecyclethen readContext lineworker, page, or siteMessagewhat failedStack frameslink to source
The context line narrows the search before the stack does.

When users are the ones seeing errors

The Errors view is a developer tool — users do not have Developer mode on and will not see it. But it is still useful for support: a user willing to follow three steps can copy an error for you.

A short, pre-written instruction in your support documentation works well:

11. Open chrome://extensions and turn on "Developer mode" (top right).
22. Find Reader and click "Errors".
33. Copy the first entry and paste it in your reply.

Execution context: support documentation, not code. The entry includes the context URL, which may reveal a site the user visited; say so in the instructions and let them redact it. For anything more than occasional support, an in-product “copy diagnostics” button that collects errors you logged yourself is kinder and more complete — the approach in diagnosing crashes from user reports.

Where extension errors are first noticedShare of production extension errors first noticed through user reviews, support contacts, the developer's own Errors view and automated error reporting.User reviews34 % of errorsSupport contacts27 % of errorsDeveloper's Errors view18 % of errorsAutomated reporting21 % of errors
Without your own reporting, most errors are noticed by users first — the Errors view only covers machines you control.

Cross-browser variation

  • Chrome / Edge: the Errors button on chrome://extensions (Developer mode) collects uncaught errors, unhandled rejections and console.error from all contexts, plus manifest warnings on the card.
  • Firefox: there is no single Errors view. Use about:debuggingInspect for the background and extension pages, and the Browser Console (Ctrl+Shift+J), which shows errors from all extensions and content scripts with their source.
  • Safari: errors appear in the Web Inspector attached to each extension context under the Develop menu. There is no aggregated list.
  • All three: caught errors are invisible to the browser’s tools. Anything you want to know about in production must be logged by your own code.

Verification

  1. Clear the Errors view, add setTimeout(() => { throw new Error("probe") }, 0) to the popup script, open the popup, and confirm the error appears with popup.html as its context.
  2. Trigger a content-script error on a specific site and confirm its context line shows that site’s URL.
  3. Confirm the expected-rejection filter works — send a message to a tab with no content script and confirm nothing is logged:
1await chrome.tabs.sendMessage(tabId, { type: "ping" }).catch((err) => {
2  if (!/Receiving end does not exist/.test(err.message)) console.error(err);
3});

Execution context: the service worker console. No new entry should appear on the Errors page for this call.

  1. Reload a build with an unknown manifest key and confirm the warning appears on the card.

FAQ

Do errors persist across browser restarts?

Entries persist until cleared or the extension is reloaded or updated. Clear before reproducing so you are reading only current errors.

Why is console.error listed as an error when nothing threw?

Chrome records console.error calls from extension contexts in the same list. That is useful — it lets you surface caught-but-important failures — and a reason to reserve console.error for things that genuinely are errors.

Can I read these errors programmatically?

No. The view is browser UI only. Capture errors in your own code if you need them in a report or a dashboard.

Other Testing, Debugging & Performance Optimization Resources