12

I am finding the 'Uncaught (in promise) Error: A listener indicated an asynchronous response by returning true, but the message channel closed before a response was received' error in the background.js. My chrome extension works but the dev tools displays a lot of these errors on background.js

I recently migrated my chrome extension from Manifest V2 to Manifest V3 and since then I am finding the error.

This is the place from where the error seems to be arising :

const browser = chrome || browser;

// Listen for messages from content script
browser.runtime.onMessage.addListener(
    function (request, sender, sendResponse) {
         var frameId = sender.frameId || 0;

            if (request.type == "connect") {               
                connect(sender.tab, frameId);
                sendResponse({ success: true });
            } else if (request.type == "disconnect") {                
                disconnect(sender.tab, frameId);
                sendResponse({ success: true });
            } else if (request.type == "send") {
                sendNativeMessage(request.data, sender.tab);
                document.addEventListener('nativeMessage',
                    function handleNativeMessage(e) {
                        sendResponse(e.detail);
                        document.removeEventListener(e.type, handleNativeMessage);
                    }, false);

               sendResponse({});                
               return true;
            }               
    });

The sendresponse is processed in ContentScript :

const browser = chrome || browser;
self.addEventListener("message", function(event){
    var request = event.data;
    if(request != null && request.type == "SendMessage")
    {
        ProcessNativeMessage(request.data);
    }
    
});

function ProcessNativeMessage(nativeMessageData) {
  var request = new Object();
  request.data = nativeMessageData;
  browser.runtime.sendMessage(request,handleExtensionResponse);
}

function handleExtensionResponse(value)
{
    //alert(value);
};

I played around by returning true, returning false, returning undefined, sending empty response and even disabling the other extensions but none of these changes worked.

I even tried changing the code with async/await as suggested here but it makes no difference.

DotNetSpartan
  • 931
  • 4
  • 20
  • 41
  • `chrome.runtime.onMessage.addListener(function(message, sender, sendResponse){ // ..code sendResponse({}); return true; });` – John Yepthomi Aug 19 '22 at 11:19
  • Keeping all your code the same just include an empty send response along with return true at the bottom outside of all the if statements. The `sendResponse({})` will keep chrome quiet for this particular call and it's aware that there will also be another response later too indicated by `return true.` – John Yepthomi Aug 19 '22 at 11:25
  • @JohnYepthomi : The sendResponse({}) at the bottom (before returning true) didn't worked. – DotNetSpartan Aug 19 '22 at 11:30
  • There's no need for `return true` in the first two ifs because they respond synchronously. Only the third if needs it, so you should move this line inside the if block. – wOxxOm Aug 19 '22 at 12:13
  • @wOxxOm I moved the empty sendResponse and return true to the third if (Please find the updated code in the question). Now it's better than before as the error is seen after 4-5 navigation clicks to native host application, Earlier the error was seen after 2-3 navigation clicks to the native host app . But the error still occurs. – DotNetSpartan Aug 19 '22 at 12:36
  • It means the problem is caused by sendMessage. Actually, if there's no problem in behavior, you can simply suppress the error by adding `.catch(e => !e.message.includes('returning true') && Promise.reject(e))` – wOxxOm Aug 19 '22 at 12:54
  • @wOxxOm The .catch(e => !e.message.includes('returning true') && Promise.reject(e)) returns Unexpected token '=>' error. – DotNetSpartan Aug 19 '22 at 13:21
  • I’m assuming sendNativeMessage() is a wrapper function? – John Yepthomi Aug 19 '22 at 13:56
  • @JohnYepthomi sendNativeMessage() is an independent synchronous function in third if. – DotNetSpartan Aug 19 '22 at 14:14
  • Can you also post the code where you handle the response. – John Yepthomi Aug 19 '22 at 14:33
  • @JohnYepthomi I've updated the question with the code that handles the response. – DotNetSpartan Aug 19 '22 at 15:15
  • `=>` is modern JS syntax, so apparently your compiler is incorrectly configured. You can use the old `function` syntax instead. The problem however is caused by the fact that your content script is listening to `message` event, so when you reload the extension or update it, the old listener is not unregistered and it tries to connect to the extension, which is no longer possible. See [Chrome extension: How to remove orphaned script after chrom extension update](https://stackoverflow.com/a/57471345) – wOxxOm Aug 19 '22 at 15:27
  • I would recommend you try using ports to connect to nativeMessaging host. It’s easy to implement. Please refer this link [Native messaging](https://developer.chrome.com/docs/apps/nativeMessaging/#native-messaging-client). Also, try disabling all other extensions and relaunch your browser. – John Yepthomi Aug 19 '22 at 16:49
  • @JohnYepthomi Yes, I have been already using ports to connect to nativeMessaging host. – DotNetSpartan Aug 19 '22 at 16:55
  • Also use ports between contentscript and backgroundscript. Same concept. Refer this link [contentscript<-port->backgroundscript](https://developer.chrome.com/docs/extensions/mv3/messaging/#connect) – John Yepthomi Aug 19 '22 at 17:07
  • @wOxxOm : The 'Uncaught (in promise)' error appears on line 1 of background.js during runtime, I tried different ways but unable to suppress it. – DotNetSpartan Aug 22 '22 at 10:51
  • The code in your question doesn't produce this error. Looking at the source code of Chromium I see this error is raised when the port is closed while communication is active, which may happen if the page/frame was removed. You can suppress the error by adding onDisconnected listener on every port and check chrome.runtime.lastError inside this listener. – wOxxOm Aug 22 '22 at 12:16
  • Why that: **sendResponse({})** before **return true** ? – Robbi Aug 22 '22 at 20:05
  • @Robbi, As John Yepthomi suggested - 'The sendResponse({}) will keep chrome quiet for this particular call and it's aware that there will also be another response later too indicated by return true'. For me it's not making much difference to the error. – DotNetSpartan Aug 23 '22 at 02:47
  • In my opinion, that's why the channel is closed. – Robbi Aug 23 '22 at 09:24
  • @Robbi : I removed that sendResponse({}), but still the error is there. – DotNetSpartan Aug 23 '22 at 09:50
  • If the error is reported in your background script, then it is your _native app_ that failed to respond to the request. In other words, `document.addEventListener('nativeMessage')` you never receive this event for one reason or another. The trick to debugging this error is to catch and rethrow it with stacktrace so you know where it is thrown, e.g. `browser.runtime.sendNativeMessage(...).catch(err => { throw new Error(err.message) }). Also, include an unique ID in the request and use console.log to make sure every request gets a response. It's a very pesky error to deal with. – Sarsaparilla Feb 28 '23 at 07:23
  • This question seems to have been answered here: – Nzube Ifechukwu Aug 03 '23 at 01:43

1 Answers1

-2

Does anything change if you rewrite the code like this?
Anyway I can't reproduce an extension with native messaging, sorry.
P.S. Before any scientist decides to downvote me badly, I want to ensure that if the solution doesn't work I'm willing to cancel the answer.

const browser = chrome || browser;

var globSendResp, globReqTypeSend;      //(*)

// Listen for messages from content script
browser.runtime.onMessage.addListener(function(request, sender, sendResponse) {
    var frameId = sender.frameId || 0;
    globReqTypeSend = false;            //(*)
    if (request.type == "connect") {               
        connect(sender.tab, frameId);
        sendResponse({ success: true });
    } else if (request.type == "disconnect") {                
        disconnect(sender.tab, frameId);
        sendResponse({ success: true });
    } else if (request.type == "send") {
        globReqTypeSend = true;         //(*)
        globSendResp = sendResponse;    //(*)
        sendNativeMessage(request.data, sender.tab);
        //sendResponse({});             //(*)
        return true;
    }
});

document.addEventListener('nativeMessage', function handleNativeMessage(e) {
    if (globReqTypeSend)
        globSendResp(e.detail)
}, false);
Robbi
  • 1,254
  • 2
  • 8
  • 11
  • Thanks for a try but I just rewrote the logic as you suggested and unfortunately it still gives the error (same as title) on line 1 of background.js. – DotNetSpartan Aug 24 '22 at 03:46