Skip to main content
Some manifest shapes make Chromium refuse to load the whole extension. The refusal surfaces as a native dialog, or as nothing at all, never as a console error. Without help, a dev session just wedges: the browser runs, the extension is absent, and the debug channel never attaches. Extension.js closes that gap in two places:
  • Before launch, it reads the built manifest.json of every extension it is about to load and warns about each refusal it can prove, naming the field and the reason.
  • At build time, it repairs a small set of unambiguous fatal shapes and prints a fix line for each repair.

Pre-launch diagnosis

These checks run against the built extension, right before the browser spawns.

Manifest version refusals

Invalid match patterns

One invalid pattern makes Chrome refuse the whole extension. Extension.js checks host_permissions, optional_host_permissions, content_scripts (matches and exclude_matches), and web_accessible_resources matches. The host grammar allows *, *.domain.tld, or a literal host. Any other wildcard placement in the host is invalid, for example https://foo.*.com/*. Ports, query strings, and fragments do not trigger a refusal, and the port may itself be a wildcard.

The load-blocker catalogue

Each of these was verified to refuse the whole extension on a live Chrome build:
  • name: missing, empty, or not a string. Chrome requires a non-empty string name.
  • version: missing, or not 1 to 4 dot-separated integers, each 0 to 65535.
  • MV3 web_accessible_resources: entries must be dictionaries with resources, plus one of matches, extension_ids, or use_dynamic_url. The MV2 string-array form refuses on MV3. MV2 keeps it legal.
  • content_scripts grammar: matches is required and must not be empty, js and css entries must be strings, run_at accepts only document_start, document_end, or document_idle, and each entry needs at least one js or css file.
  • minimum_chrome_version: an invalid value refuses outright. A valid value above the resolved browser’s version refuses too, so the check compares against the binary that the session launches.
  • commands: Chrome allows at most 4 shortcuts with a suggested_key. Firefox has no cap, so ported Firefox extensions routinely trip this.
  • key: must be a valid base64 public key. Broken padding refuses the extension.
  • Icons: a manifest icon (icons.* or any *_action.default_icon) whose file is missing or 0 bytes refuses the whole extension.
  • Locales: a declared default_locale whose _locales/<locale>/messages.json is missing or not valid JSON refuses. So does a whole-string __MSG_key__ reference that the catalog does not define (the lookup is case-insensitive, @@predefined names are exempt). A populated _locales tree with no default_locale in the manifest refuses too.
  • storage.managed_schema: a schema path that does not exist inside the extension directory refuses the whole extension.
Each finding prints as a warn naming the extension path and every blocker, before the spawn, so the wedge is explained up front.

Automatic repairs at build time

A subset of fatal shapes is unambiguous enough to fix. During the build, Extension.js repairs these in the emitted manifest.json: Every repair reports a fix line in the CLI output at the moment it happens, and records a manifest.json build warning, so nothing is rewritten silently.
Repairs apply to the emitted dist manifest only. Your source manifest.json is never modified. Fix the source when you see a fix line, so the repair stops being needed.

Next steps