Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chrome: "The message port closed before a response was received." #130

Closed
lydell opened this issue Jun 19, 2018 · 14 comments

Comments

@lydell
Copy link
Contributor

@lydell lydell commented Jun 19, 2018

Minimal repro repo:
https://github.com/lydell/webextension-polyfill-messaging-issue

This happens with both v0.2.1 on npm and when built from commit 2537b23.

Summary

If a browser.runtime.onMessage callback does not return a Promise, browser.runtime.sendMessage will be rejected with the following error, causing noise in the console:

"The message port closed before a response was received."

Workaround

Even if you don't want to send a response, always return a promise
in your onMessage callback:

// background.js
browser.runtime.onMessage.addListener(message => {
  console.log("background: onMessage", message);

  // Add this line:
  return Promise.resolve("Dummy response to keep the console quiet");
});

You can also make the onMessage callback async to implicitly return a Promise (resolving to undefined in the below example).

// background.js
// Notice the `async` keyword.
browser.runtime.onMessage.addListener(async message => {
  console.log("background: onMessage", message);
});

Files

Copied over for convenience from:
https://github.com/lydell/webextension-polyfill-messaging-issue

{
  "manifest_version": 2,
  "version": "0.0.0",
  "name": "Test",
  "background": {
    "scripts": [
      "browser-polyfill-npm.js",
      "background.js"
    ]
  },
  "content_scripts": [
    {
      "matches": [
        "<all_urls>"
      ],
      "js": [
        "browser-polyfill-master.js",
        "content.js"
      ]
    }
  ]
}
// background.js

browser.runtime.onMessage.addListener(onMessage);

function onMessage(message) {
  console.log("background: onMessage", message);

  // 1: Causes the following to be logged in content:
  // "The message port closed before a response was received."
  return undefined;

  // 2: Causes this response to be logged in content, as expected.
  // return Promise.resolve("response from background");

  // 3: Causes this error to be logged in content, as expected.
  // return Promise.reject(new Error("Could not respond"));

  // 4: Causes nothing at all to be logged in content!
  // I guess it is waiting for the deprecated `sendResponse` parameter to be
  // called.
  // return true;
}
// content.js

// 1: Unless background returns a Promise in its onMessage, this promise is
// rejected with:
// "The message port closed before a response was received."
browser.runtime
  .sendMessage("hello from content")
  .then(console.log, console.error);



// 2: This does not seem to cause any errors:
// chrome.runtime.sendMessage("hello from content");
// console.log("content: after chrome.runtime.sendMessage", chrome.runtime.lastError);



// 3: Inside the callback, `chrome.runtime.lastError` will be:
// "The message port closed before a response was received."
// It seems like if `sendMessage` defines a callback but the other end doesn't
// respond, Chrome is treating that as an error. Which makes sense.
// The question is how this should be handled in a Promise based API.
// chrome.runtime.sendMessage("hello from content", response => {
//   console.log("content: callback", response, chrome.runtime.lastError);
// });
// console.log(
//   "content: after chrome.runtime.sendMessage with callback",
//   chrome.runtime.lastError
// );

Solution?

Should the "The message port closed before a response was received." be detected, and the promise should be resolved with undefined?

lydell added a commit to lydell/webextension-polyfill that referenced this issue Jun 19, 2018
@Rob--W

This comment has been minimized.

Copy link
Member

@Rob--W Rob--W commented Jun 19, 2018

Thanks for this report - I can confirm that this happens with and without --enable-features=NativeCrxBindings .

lydell added a commit to lydell/LinkHints that referenced this issue Jun 25, 2018
Use webextension-polyfill fork to fix
mozilla/webextension-polyfill#130

Make sure no `onMessage` listeners are `async`. `WorkerProgram` and
`RendererProgram` both listen to all messages from background, but only
handle the ones meant for them based on an `if` statement. However, if
the listener is an `async` function it will *always* return a Promise,
indicating that the listener wants to send a response. It is only
allowed to send *one* response per message per document. Otherwise
Chrome shows an error.
@rpl rpl closed this in #140 Jul 4, 2018
soruly added a commit to soruly/trace.moe-WebExtension that referenced this issue Feb 23, 2019
@sabrinasong

This comment has been minimized.

Copy link

@sabrinasong sabrinasong commented Mar 21, 2019

What if the content script goes away after receiving the message, and cannot send a response?

@Rob--W

This comment has been minimized.

Copy link
Member

@Rob--W Rob--W commented Mar 22, 2019

What if the content script goes away after receiving the message, and cannot send a response?

Then the sendMessage promise is rejected with an object with a "message" property.

In Firefox, the message is "Message manager disconnected"
In Chrome, the message is "The message port closed before a response was received."

@OussamaBATOUCHE

This comment has been minimized.

Copy link

@OussamaBATOUCHE OussamaBATOUCHE commented Mar 25, 2019

hey , can some one give me simple solution

@prathmesh4

This comment has been minimized.

Copy link

@prathmesh4 prathmesh4 commented Apr 12, 2019

Unchecked runtime.lastError: The message port closed before a response was received.
error

@RobertJGabriel

This comment has been minimized.

Copy link

@RobertJGabriel RobertJGabriel commented Apr 19, 2019

Add a return true. It will force chrome to wait for the response.

chrome.extension.onMessage.addListener((request, sender, sendResponse) => {
  // Look up a term from the dictionary using the Ajax API.
  const lookupURL = `http://dictionary-lookup.org/${request.arg}`;
  sendRequest(lookupURL)
    .then(resp => {
      sendResponse(resp || '{}');
    })
    .catch(error => {
      sendResponse('{}');
    });
  return true; // Inform Chrome that we will make a delayed sendResponse
});

example

@vrgomes

This comment has been minimized.

Copy link

@vrgomes vrgomes commented Jul 9, 2019

i think that the: return true; // Inform Chrome that we will make a delayed sendResponse

Doesn't solve the issue.
Greetings.

@reZach

This comment has been minimized.

Copy link

@reZach reZach commented Aug 8, 2019

@vrgomes is correct, this fix does not work - is there another resolution to this issue?

@vrgomes

This comment has been minimized.

Copy link

@vrgomes vrgomes commented Aug 21, 2019

Any updates on this?
Greetings.

@reZach

This comment has been minimized.

Copy link

@reZach reZach commented Sep 15, 2019

Using @RobertJGabriel 's answer as a place to start, I found the error occurs when we neglect to send a response at all. I found I needed to call sendResponse in addition to returning true to prevent the error from happening. It doesn't matter that the object we send is empty. @vrgomes hope this helps

chrome.runtime.onMessage.addListener(function(message, sender, sendResponse){
    // ..code
    sendResponse({});
    return true;
});
@stanleykayzz

This comment has been minimized.

Copy link

@stanleykayzz stanleykayzz commented Oct 9, 2019

Hello, in my case I call sendResponse in my background.js then return true but like @vrgomes said are just delayed so the only difference is that I get error messages later in my background console.

@vrgomes

This comment has been minimized.

Copy link

@vrgomes vrgomes commented Oct 9, 2019

Using @RobertJGabriel 's answer as a place to start, I found the error occurs when we neglect to send a response at all. I found I needed to call sendResponse in addition to returning true to prevent the error from happening. It doesn't matter that the object we send is empty. @vrgomes hope this helps

chrome.runtime.onMessage.addListener(function(message, sender, sendResponse){
    // ..code
    sendResponse({});
    return true;
});

@reZach it looks like to work that way!
But had to put on the content script on all calls this check:
if(response == undefined || Object.keys(response).length == 0) return;

Greetings.

@reZach

This comment has been minimized.

Copy link

@reZach reZach commented Oct 9, 2019

Yes, you will need that too @vrgomes. I forgot to put that in my reply.

@Rob--W

This comment has been minimized.

Copy link
Member

@Rob--W Rob--W commented Oct 10, 2019

The recent comments are about the non-polyfilledchrome messaging API.

The original reported issue has been fixed a long time ago (in version 0.3.0) by #140 . If you still encounter this issue, upgrade the polyfill to the latest version. If you can still reproduce this issue despite using the latest version, please file a new issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
9 participants
You can’t perform that action at this time.