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
- Retry on a normal http(s) page — restricted schemes can never be injected
- Verify the manifest declares the 'scripting' permission and host_permissions/<all_urls> (or the tab's origin)
- Reload the tab after an extension reload/update, then re-trigger the scan
- 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
- Gate the inject-fallback action on tab URL scheme before messaging the worker
- Keep 'scripting' permission and broad host_permissions in the manifest
- Reload tabs after extension updates before re-scanning them
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.