1

I am developing a web extension with a custom devtools panel that injects a content script via the scripting API. The content script then sends a message via chrome.runtime.sendMessage, which the devtools panel is listening to. Here is a minimal sample of this flow (in the panel):

function onMessageFromContentScript(message) {
  // React to message
}

async function injectContentScript() {
  chrome.runtime.onMessage.addListener(onMessageFromContentScript);
  const tabId = chrome.devtools.inspectedWindow.tabId;
  await chrome.scripting.executeScript({
    func: () => {
      chrome.runtime.sendMessage({
        id: "injected"
      });
    },
    target: {
      tabId,
    }
  });
}

This works fine in regular tabs, however while in incognito mode an error is thrown instead

Uncaught (in promise) Error: Could not establish connection. Receiving end does not exist.

According to the MV3 docs there are some limitations for extensions which are in the default spanning mode, specifically:

The default mode is "spanning", which means that the extension will run in a single shared process. Any events or messages from an incognito tab will be sent to the shared process, with an incognito flag indicating where it came from. Because incognito tabs cannot use this shared process, an extension using the "spanning" incognito mode will not be able to load pages from its extension package into the main frame of an incognito tab.

(Source: https://developer.chrome.com/docs/extensions/mv3/manifest/incognito/#spanning)

While switching the incognito mode to split seems to solve the problem, I don't understand the exact limitations mentioned in the documentation. I confirmed that the content script is still injected, it is only the message channel that seems to be broken. If the injection is triggered from a popup instead of a devtools page it also seems to work fine in spanning mode.

My questions are:

  1. What exactly does the section in the Chrome docs mean, what are the limitations and which APIs won't work?

  2. Is there an alternative to fix the problem besides switching the incognito mode? The split mode might have some unwanted side effects on other features. Additionally it is not supported in Firefox according to https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/incognito

I pushed a sample extension showing the behavior to https://github.com/StefanBlamberg/chrome-ext-spanning-issue which can be loaded in Chrome in order to reproduce the issue.

Stefan Blamberg
  • 816
  • 9
  • 24

1 Answers1

1

Looks like a bug in Chrome: chrome-extension:// page inside incognito devtools is effectively running in a split mode (it's a different process of the incognito window) and that contradicts the default spanning mode's expectation of a single extension process.

The workaround is to use chrome.devtools.inspectedWindow.eval instead of executeScript and specify useContentScriptContext to imitate executeScript's default behavior.

function injectContentScript() {
  chrome.devtools.inspectedWindow.eval(`(${() => {
    return {id: "injected"};
  }})()`, {useContentScriptContext: true}, (res, err) => {
    document.body.append(document.createElement('br'), JSON.stringify({res, err}));
  });
}
wOxxOm
  • 65,848
  • 11
  • 132
  • 136