Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Receiving end does not exist" when passing message to injected content script

In an add-on for Firefox, I'm trying to inject code from a background script into a tab and then pass a message to it. Unfortunately, the content script seems to add the listener only after the message has already been sent, resulting in in error. What am I missing? Here is my sample code:

manifest.json:

{
    "description": "Test background to content message passing",
    "manifest_version": 2,
    "name": "Background content message passing",
    "version": "0.1.0",
    "default_locale": "en",

    "applications": {
        "gecko": {
            "id": "[email protected]",
            "strict_min_version": "51.0"
        }
    },

    "permissions": [
        "contextMenus",
        "<all_urls>"
    ],

    "background": {
        "scripts": ["background.js"]
    }
}

background.js:

"use strict";

const {contextMenus, i18n, runtime, tabs} = browser;

contextMenus.onClicked.addListener(function(info, tab) {
    if (info.menuItemId == "bgd-cnt-msg") {
        tabs.executeScript(tab.id, {
            file: "/content.js",
        })
        .then(runtime.sendMessage({"result": 42}))
        .then(console.log("Debug: runtime message sent"))
        .catch(console.error.bind(console));
    }
});

contextMenus.create({
    id: "bgd-cnt-msg",
    title: "Test message passing",
    contexts: ["all"],
    documentUrlPatterns: ["<all_urls>"]
});

content.js

"use strict";

console.log("Debug: executing content script");

browser.runtime.onMessage.addListener(function (message) {
    console.log("Debug: received message %O", message);
});

console.log("Debug: added listener");

The result of selecting the the context menu entry is

Debug: runtime message sent                                  background.js:11:15
Debug: executing content script                                     content.js:3
Debug: added listener                                               content.js:9
Error: Could not establish connection. Receiving end does not exist.   undefined

I.e., the context scripts executes after the message to the tab is sent. How can I add the listener before sending the message?


As suggested by @Thắng, I changed my code to use tabs.sendMessage instead of runtime.sendMessage:

contextMenus.onClicked.addListener(function(info, tab) {
    if (info.menuItemId == "bgd-cnt-msg") {
        tabs.executeScript(tab.id, {
            file: "/content.js",
        })
        .then(tabs.sendMessage(tab.id, {"result": 42}))
        .then(console.log("Debug: runtime message sent"))
        .catch(console.error.bind(console));
    }
});

Now the error is reported a little earlier:

Debug: runtime message sent                                  background.js:11:15
Error: Could not establish connection. Receiving end does not exist.   undefined
Debug: executing content script                                     content.js:3
Debug: added listener                                               content.js:9

Thanks to @Thắng, who provided a working solution, I fixed my code to not only use tabs.sendMessage but also pass functions for the callbacks:

contextMenus.onClicked.addListener(function(info, tab) {
    if (info.menuItemId == "bgd-cnt-msg") {
        tabs.executeScript(tab.id, {
            file: "/content.js",
        })
        .then(function () { tabs.sendMessage(tab.id, {"result": 42}) })
        .then(function () { console.log("Debug: runtime message sent") })
        .catch(console.error.bind(console));
    }
});

With an additional fix in content.js

browser.runtime.onMessage.addListener(function (message) {
    console.log("Debug: result is " + message.result);
});

I now get

Debug: executing content script                                     content.js:3
Debug: added listener                                               content.js:9
Debug: runtime message sent                                  background.js:11:15
Debug: result is 42                                                 content.js:6
like image 533
maf Avatar asked Mar 15 '26 03:03

maf


1 Answers

In background script, you need to let it know it should send the message to which tab, so don't use runtime.sendMessage for this.

var sending = chrome.tabs.sendMessage(
  tabId,                   // integer
  message,                 // any
  options                  // optional object
)

See more here (for webExtensions but also compatible with Chrome): https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/tabs/sendMessage

Your fully working extension here (you may need to change all the browser.* to chrome.*): https://drive.google.com/file/d/1KGf8tCM1grhhiC9XcHOjsrbBsIZGff3e/view?usp=sharing

like image 64
Thắng Trần Xuân Avatar answered Mar 16 '26 16:03

Thắng Trần Xuân



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!