pbakaus/impeccable · error

extension/manifest.json: expected background.service_worker

Error message

extension/manifest.json: expected background.service_worker to derive the Firefox manifest

What it means

Thrown by the Firefox-extension build step when the Chrome extension manifest lacks background.service_worker. The Firefox (AMO) manifest is DERIVED from the Chrome manifest by converting the service worker into an event-page script, so a missing service_worker means the transform has no source value and cannot proceed.

Source

Thrown at scripts/build-extension.js:97

    `zip -r ${JSON.stringify(zipPath)} .${exArgs ? ' ' + exArgs : ''}`,
    { cwd, stdio: 'pipe' },
  );
  const size = fs.statSync(zipPath).size;
  console.log(`Packaged ${path.relative(ROOT, zipPath)} (${(size / 1024).toFixed(1)} KB)`);
}

// --- 3a. Chrome zip (manifest unchanged) ---

packZip(path.join(DIST, 'extension.zip'), EXT_DIR, ['STORE_LISTING.md', '*.DS_Store']);

// --- 3b. Firefox: derive a Gecko-compatible manifest and stage an unpacked
// build (consumed by `web-ext lint` in CI), then zip it for AMO. ---

const chromeManifest = JSON.parse(fs.readFileSync(path.join(EXT_DIR, 'manifest.json'), 'utf-8'));

const serviceWorker = chromeManifest.background?.service_worker;
if (!serviceWorker) {
  throw new Error(
    'extension/manifest.json: expected background.service_worker to derive the Firefox manifest',
  );
}

const firefoxManifest = {
  ...chromeManifest,
  // Gecko supports MV3 via non-persistent event pages. Declaring `scripts`
  // (rather than `service_worker`) is the path supported across all MV3 Firefox
  // releases; service-worker.js uses only top-level listeners + an in-memory
  // Map, so it runs unchanged as an event page.
  background: { scripts: [serviceWorker] },
  // Required by AMO for signing/distribution. Ignored by Chrome.
  browser_specific_settings: {
    gecko: {
      id: 'impeccable@bakaus.com',
      // `data_collection_permissions` (below) is required by AMO for new
      // submissions and is only honored on Firefox 140+. We set the floor to
      // 140 so the declared min version actually supports every key we ship;

View on GitHub (pinned to d14711ae3d)

Solutions

  1. Open extension/manifest.json and confirm `background.service_worker` (e.g. "background.service_worker": "service-worker.js") is present and points at the worker file.
  2. If you intentionally moved off a service worker, update scripts/build-extension.js to derive the Firefox background block from whatever source shape you now use.
  3. Re-run `bun run build:extension` after fixing the manifest.

Example fix

// before — extension/manifest.json
{
  "manifest_version": 3,
  "background": {}
}

// after
{
  "manifest_version": 3,
  "background": { "service_worker": "service-worker.js" }
}
Defensive patterns

Strategy: validation

Validate before calling

const manifest = JSON.parse(fs.readFileSync(path.join(EXT_DIR, 'manifest.json'), 'utf-8'));
if (!manifest.background?.service_worker) {
  throw new Error('Add background.service_worker to extension/manifest.json before building Firefox.');
}

Type guard

function hasServiceWorker(manifest) {
  return typeof manifest?.background?.service_worker === 'string' && manifest.background.service_worker.length > 0;
}

Try / catch

try {
  buildFirefoxExtension();
} catch (err) {
  if (/background.service_worker/.test(err.message)) {
    console.error('Firefox build needs background.service_worker in the Chrome manifest.');
  } else throw err;
}

Prevention

When it happens

Trigger: Running scripts/build-extension.js when extension/manifest.json has no top-level background object, or has background.scripts instead of background.service_worker, or the MV3 service worker key was removed/renamed during a manifest edit.

Common situations: Refactoring the extension to a different background model (e.g. switches to background.scripts for MV2 compat) without updating the Firefox derivation; a manifest rewrite that dropped the background block; building the extension from a stale checkout after the manifest schema changed.

Related errors


AI-assisted analysis of pbakaus/impeccable@d14711ae3d (2026-08-13). Data as JSON: /api/errors/3a8aaa2266c59d5a. Report an issue: GitHub.