pbakaus/impeccable · warning

[impeccable] Fallback injection failed:

Error message

[impeccable] Fallback injection failed:

What it means

In the impeccable Chrome extension, when page CSP blocks the detector, the content script asks the background service worker to inject detector/detect.js into the page's MAIN world via chrome.scripting.executeScript. If that promise rejects — restricted page, missing host/scripting permission, invalidated context — the worker logs '[impeccable] Fallback injection failed:' and the page simply does not get the detector.

Source

Thrown at extension/background/service-worker.js:149

    notifyPanels(tabId, { action: 'overlays-toggled', visible: msg.visible });
    chrome.runtime.sendMessage({ action: 'overlays-toggled-broadcast', tabId, visible: msg.visible }).catch(() => {});
    sendResponse({ ok: true });
  }

  else if (msg.action === 'get-state' && tabId) {
    sendResponse(getState(tabId));
  }

  else if (msg.action === 'inject-fallback' && tabId) {
    // CSP fallback: inject detector via chrome.scripting (bypasses page CSP)
    chrome.scripting.executeScript({
      target: { tabId },
      world: 'MAIN',
      files: ['detector/detect.js'],
    }).then(() => {
      // Detector will post impeccable-ready, content script handles the rest
    }).catch((err) => {
      console.warn('[impeccable] Fallback injection failed:', err);
    });
    sendResponse({ ok: true });
  }

  else if (msg.action === 'disabled-rules-changed') {
    // Re-scan all tabs that have been injected
    for (const [tid, state] of tabState) {
      if (state.injected) sendScanToTab(tid);
    }
    sendResponse({ ok: true });
  }

  return true;
});

// Track which tabs have DevTools open (via the devtools.js lifecycle port)
const devtoolsTabs = new Set();

View on GitHub (pinned to f88b2837a7)

Solutions

  1. Retry on a normal http(s) page — restricted schemes can never be injected
  2. Verify the manifest declares the 'scripting' permission and host_permissions/<all_urls> (or the tab's origin)
  3. Reload the tab after an extension reload/update, then re-trigger the scan
  4. Treat the warning as benign on chrome:// pages; there is nothing to detect there

Example fix

// before
chrome.scripting.executeScript({ target: { tabId }, world: 'MAIN', files: ['detector/detect.js'] });
// after: skip pages the API can never touch
const url = new URL(tab.url || 'about:blank');
if (!/^https?:$/.test(url.protocol)) return;
chrome.scripting.executeScript({ target: { tabId }, world: 'MAIN', files: ['detector/detect.js'] });
Defensive patterns

Strategy: validation

Validate before calling

// Only attempt MAIN-world injection on injectable pages
function isInjectable(tab) {
  try {
    const u = new URL(tab.url || '');
    return (u.protocol === 'http:' || u.protocol === 'https:')
      && !u.hostname.endsWith('chrome.google.com'); // web store is restricted too
  } catch { return false; }
}

Try / catch

chrome.scripting.executeScript({ target: { tabId }, world: 'MAIN', files: ['detector/detect.js'] })
  .catch((err) => { if (!isRestrictedPageError(err)) console.warn(err); }); // log, never throw from the handler

Prevention

When it happens

Trigger: Sending inject-fallback for a chrome://, edge://, chrome-extension://, Chrome Web Store, or PDF-viewer tab; a tab whose origin is not covered by host_permissions; the MV3 service worker restarting and holding a stale tabId after the extension was reloaded/updated.

Common situations: User triggers the extension on browser-internal pages; extension reloaded during development so previously injected tabs have dead contexts; 'scripting' permission removed from the manifest during testing.

Related errors


AI-assisted analysis of pbakaus/impeccable@f88b2837a7 (2026-08-18). Data as JSON: /api/errors/e45fb9af8498dc73. Report an issue: GitHub.