18

There are plenty of issues open on the subject, but I couldn't find an explanation in my case. Here is a minimal test case:

Here is my manifest.json

{
  "manifest_version": 3,
  "name": "Test",
  "version": "1.0",
  "description": "Test extension",
  "icons": {
    "48": "dark.png"
  },
  "background": {
    "service_worker": "button.js"
  },
  "permissions": [
    "activeTab"
  ],
  "action": {
    "default_icon": "dark.png",
    "default_title": "DarkTheme"
  },
  "content_scripts": [
    {
      "matches": [
        "<all_urls>"
      ],
      "js": [
        "dark.js"
      ]
    }
  ]
}

button.js

chrome.action.onClicked.addListener(tab => {
  console.log('clicked')
  chrome.tabs.sendMessage(tab.id, { value: false })
});

dark.js

chrome.runtime.onMessage.addListener(request => {
  console.log('received', request)
})

So, basically, my listener is set right at the start, and only when I press the button do I send a message. How come I can receive this error when I press the button?

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

Tested on Chromium Version 100.0.4896.75 (Build officiel) snap (64 bits)

Sharcoux
  • 5,546
  • 7
  • 45
  • 78
  • 4
    See [Chrome extension content script re-injection after upgrade or install](https://stackoverflow.com/q/10994324) - it's because content scripts don't auto-run after you reload the extension. – wOxxOm Apr 12 '22 at 20:52
  • That's why it was so random! My god. Firefox seems to automatically reload the scripts so I would not have think of that. – Sharcoux Apr 12 '22 at 21:02

5 Answers5

14

Thanks for posting, I also had a similar issue and for my particular problem I could not find a proper answer in particular for Google Chrome Extension Manifest Version 3.

In my case, I want to send the idle state with chrome.idle.onStateChanged from a background.js to a contentScript.js. As I am building an extension for reddit, the contentScript.js is only injected into pages which match the URL pattern for reddit.

chrome.idle.onStateChanged.addListener(
  (browserActivityState) => {
    chrome.tabs.query({active: true, currentWindow: true}, (tabs) => {
        chrome.tabs.sendMessage(tabs[0].id, { browserActivityState: browserActivityState });
    });
  }
)

Then I got the same error as you.

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

I realized while reading the error message, that this happened because I want to send a message to a page which does not have contentScript.js.

I also noticed that it occurred for when I had Chrome but not a reddit page open, I then for example locked my screen which triggers an idle change event and hence my background.js tries send a message to a page.

The problem is, reddit has not been open in the last active tab and therefore the tab to which this message has been sent does not have a contentScript.js injected.

As preliminary solution, not sure if this is the best style but it does the job, I check if the tab I am sending a message to does match the URL of pages where I am injecting the contentScript.js into with if (tabs[0].url.match('https:\/\/.*.reddit.com\/.*')).

chrome.idle.onStateChanged.addListener(
  (browserActivityState) => {
    console.log('browserActivityState changed')
    chrome.tabs.query({active: true, currentWindow: true}, (tabs) => {
      if (tabs[0].url.match('https:\/\/.*.reddit.com\/.*')) {
        chrome.tabs.sendMessage(tabs[0].id, { browserActivityState: browserActivityState });
      }
    });
  }
)

This ensures, I am not sending a message to a tab with 'no receiving end' and so far the error is gone.

Maybe you can look in this direction as well for your problem solving.

I hope I was able to help a bit.

simon
  • 141
  • 1
  • 3
  • This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/32435194) – Minion3665 Aug 12 '22 at 09:09
  • For me, it was a certain piece of this answer that did it for me: I used runtime.sendMessage instead of tabs.sendMessage. – Nekoseri Aug 04 '23 at 23:22
7

It took me hours to figure out the cause of this error because everything in my code seems correct. Turns out I just need to refresh both the extension and the webpage to see it working.

Liutong Chen
  • 2,915
  • 5
  • 22
  • 29
3

Had this and a lot of more errors. Removed all of them by setting Evernote Chrome extention to 'look only on press' (or simply disabled). Solution from https://stackoverflow.com/a/75723433/17137584

There was 2 types of errors, each of up to ten variations (different ends):

commons.js:2 Channel: Error in handleResponse UNK/SW_UNREACHABLE ...

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

Dmytrq
  • 77
  • 8
1

I had some issues with this followed the docs here as stated above https://developer.chrome.com/docs/extensions/mv3/messaging/ this works for v3

popup.js

chrome.tabs.query({
    active: true,
    currentWindow: true
}, function(tabs) {
    chrome.scripting.executeScript({
        target: {
            tabId: tabs[0].id
        },
        function: sendData,
    });
});

const sendData = async () => {

    chrome.runtime.sendMessage({
        count: 12,
        data: []
    }, function(response) {
        console.log(response.received);
    });

}

Background.js

chrome.runtime.onMessage.addListener((data, sender, sendResponse) => {
    if (data) {
        // Do something amazing
    }
    sendResponse({
        received: true
    });
});
user1503606
  • 3,872
  • 13
  • 44
  • 78
0

When sending message from content script to background, it should be like below.

chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
   chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response) {
     console.log(response.farewell);
   });
});

Link: https://developer.chrome.com/docs/extensions/mv3/messaging/

lKotan
  • 1
  • 1
  • 2
  • 3
    This applies for a scenario "background > content script", not the other way around. Your content script can't query for chrome tabs.If you want to send a message from your content script to your background script, you'd use `chrome.runtime.sendMessage()` – kano Feb 23 '23 at 07:40