How to avoid “Extension context invalidated” errors when messaging AFTER an Extension update?

When an extension is unloaded, the existing content scripts lose their connection to the rest of the extension—i.e. ports close, and they would be unable to use runtime.sendMessage()—but the content scripts themselves still continue to work, as they’re already injected into their pages.

It’s the same when an extension is reloaded: those existing content scripts will still be there, but unable to send messages; attempts to do so cause errors like the one you’re encountering. Further, as it’s common for extensions to inject their content scripts into existing tabs when they are loaded (on Chrome—Firefox does that automatically), you’ll end up with more than one copy of the content script running in a given tab: the original, now-disconnected one, and the current, connected one.

Problems can arise if either: (1) your original content script is still trying to communicate with the rest of the extension or (2) your original content script does things like modify the DOM, as you could end up with those changes done more than once.

That’s probably why you’re still getting the error even after re-injecting your content scripts: the error is coming from the original content script that’s still there, but disconnected.

This has paraphrased some helpful background information that I found when previously researching this problem. Note that Firefox automatically unloads content scripts (more on that later).

Solutions

If you are not automatically re-injecting your content scripts, then you can try to get the existing script to reconnect on upgrade, as per wOxxOm‘s comment above.

Here’s some further info and advice, particularly useful if you inject new content scripts and want to disable the original, disconnected, one when a new one is injected.

Regardless of whether you would like to try to reconnect using the existing content script, or stop the original content script from making further changes and inject a new one, you need to detect that an unload has occurred. You can use the port’s disconnect handler to catch when your extension is unloaded. If your extension only uses simple one-time message passing, and not ports, then that code is as simple as running the following when your content script starts up (I first saw this technique in some code from lydell).

browser.runtime.connect().onDisconnect.addListener(function() {
    // clean up when content script gets disconnected
})

On Firefox, the port’s disconnect is not fired, because the content scripts are removed before they would receive it. This has the advantage that this detection isn’t necessary (nor is manual content script injection, as content scripts are injected automatically too), but it does mean that there’s no opportunity to reset any changes made to the DOM by your content script when it was running.

Leave a Comment