parcel-bundler/parcel · error · ThrowableDiagnostic

Invalid Web Extension manifest

Error message

Invalid Web Extension manifest

What it means

Thrown by @parcel/transformer-webextension when manifest.json declares default_locale but the expected localization files are missing. The transformer checks the _locales directory (err='key' if the directory itself is absent) and the messages.json inside the locale subfolder (err='value' if the file is missing). The diagnostic highlights the /default_locale pointer in the manifest.

Source

Thrown at packages/transformers/webextension/src/WebExtensionTransformer.js:61

  hmrOptions: ?HMROptions,
) {
  const hot = Boolean(hmrOptions);
  const fs = asset.fs;
  const filePath = asset.filePath;
  const assetDir = path.dirname(filePath);
  const isMV2 = program.manifest_version == 2;
  delete program.$schema;
  if (program.default_locale) {
    const locales = path.join(assetDir, '_locales');
    let err = !(await fs.exists(locales))
      ? 'key'
      : !(await fs.exists(
          path.join(locales, program.default_locale, 'messages.json'),
        ))
      ? 'value'
      : null;
    if (err) {
      throw new ThrowableDiagnostic({
        diagnostic: [
          {
            message: 'Invalid Web Extension manifest',
            origin: '@parcel/transformer-webextension',
            codeFrames: [
              {
                filePath,
                codeHighlights: [
                  {
                    ...getJSONHighlightLocation(ptrs['/default_locale'], err),
                    message: md`Localization ${
                      err == 'value'
                        ? 'file for ' + program.default_locale
                        : 'directory'
                    } does not exist: ${path.relative(
                      assetDir,
                      path.join(locales, program.default_locale),
                    )}`,

View on GitHub (pinned to 59484858a1)

Solutions

  1. Create _locales/<default_locale>/messages.json relative to manifest.json.
  2. Ensure the locale code in default_locale exactly matches the subdirectory name.
  3. Remove the default_locale field if the extension has no internationalization.

Example fix

// before
{ "default_locale": "en" }  // no _locales/en/messages.json
// after
create file: _locales/en/messages.json with { "msg": { "message": "..." } }
Defensive patterns

Strategy: validation

Validate before calling

const fs = require('fs').promises;
const path = require('path');
if (manifest.default_locale) {
  const dir = path.join(assetDir, '_locales', manifest.default_locale);
  const file = path.join(dir, 'messages.json');
  await fs.access(dir).catch(() => { throw new Error('Missing _locales/' + manifest.default_locale); });
  await fs.access(file).catch(() => { throw new Error('Missing messages.json for ' + manifest.default_locale); });
}

Prevention

When it happens

Trigger: collectDependencies runs with program.default_locale truthy; fs.exists(assetDir/_locales) is false (key error) OR fs.exists(assetDir/_locales/<default_locale>/messages.json) is false (value error).

Common situations: Manifest sets "default_locale": "en" but the _locales directory was never created, the locale code is wrong (en vs en_US), or messages.json was renamed/moved out of the locale folder.

Related errors


AI-assisted analysis of parcel-bundler/parcel@59484858a1 (2026-08-13). Data as JSON: /api/errors/1682f8223067c5b7. Report an issue: GitHub.