{"record":{"id":"e45fb9af8498dc73","repo":"pbakaus/impeccable","slug":"impeccable-fallback-injection-failed","errorCode":null,"errorMessage":"[impeccable] Fallback injection failed:","messagePattern":"\\[impeccable\\] Fallback injection failed:","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"extension/background/service-worker.js","lineNumber":149,"sourceCode":"    notifyPanels(tabId, { action: 'overlays-toggled', visible: msg.visible });\n    chrome.runtime.sendMessage({ action: 'overlays-toggled-broadcast', tabId, visible: msg.visible }).catch(() => {});\n    sendResponse({ ok: true });\n  }\n\n  else if (msg.action === 'get-state' && tabId) {\n    sendResponse(getState(tabId));\n  }\n\n  else if (msg.action === 'inject-fallback' && tabId) {\n    // CSP fallback: inject detector via chrome.scripting (bypasses page CSP)\n    chrome.scripting.executeScript({\n      target: { tabId },\n      world: 'MAIN',\n      files: ['detector/detect.js'],\n    }).then(() => {\n      // Detector will post impeccable-ready, content script handles the rest\n    }).catch((err) => {\n      console.warn('[impeccable] Fallback injection failed:', err);\n    });\n    sendResponse({ ok: true });\n  }\n\n  else if (msg.action === 'disabled-rules-changed') {\n    // Re-scan all tabs that have been injected\n    for (const [tid, state] of tabState) {\n      if (state.injected) sendScanToTab(tid);\n    }\n    sendResponse({ ok: true });\n  }\n\n  return true;\n});\n\n// Track which tabs have DevTools open (via the devtools.js lifecycle port)\nconst devtoolsTabs = new Set();\n","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/pbakaus/impeccable/blob/f88b2837a7d7c3182e46307bbbb091a1ed547571/extension/background/service-worker.js#L131-L167","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nchrome.scripting.executeScript({ target: { tabId }, world: 'MAIN', files: ['detector/detect.js'] });\n// after: skip pages the API can never touch\nconst url = new URL(tab.url || 'about:blank');\nif (!/^https?:$/.test(url.protocol)) return;\nchrome.scripting.executeScript({ target: { tabId }, world: 'MAIN', files: ['detector/detect.js'] });","handlingStrategy":"validation","validationCode":"// Only attempt MAIN-world injection on injectable pages\nfunction isInjectable(tab) {\n  try {\n    const u = new URL(tab.url || '');\n    return (u.protocol === 'http:' || u.protocol === 'https:')\n      && !u.hostname.endsWith('chrome.google.com'); // web store is restricted too\n  } catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"chrome.scripting.executeScript({ target: { tabId }, world: 'MAIN', files: ['detector/detect.js'] })\n  .catch((err) => { if (!isRestrictedPageError(err)) console.warn(err); }); // log, never throw from the handler","preventionTips":["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"],"tags":["chrome-extension","content-script","csp-fallback","scripting-api","permissions"],"backgroundTag":"chrome-scripting-injection-failed","analyzedSha":"f88b2837a7d7c3182e46307bbbb091a1ed547571","analyzedAt":"2026-08-18T04:58:36.608Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}