Uncaught (in promise) Error: A listener indicated an asynchronous response by returning true, but the message channel closed before a response was received

The error message suggests an issue in the communication process between the listener and the message channel. Upon sending a response indicating its readiness to receive a message, the listener encountered a challenge as the message channel unexpectedly closed before the message could be received. This interruption in the communication flow led to the error notification.

Solution

The common cause for this issue is invoking chrome.runtime.sendMessage when the popup is not displayed. Since the popup remains hidden, it cannot receive any messages. To prevent the error, you can handle it by using '()=>chrome.runtime.lastError' instead of 'function(response){}'. This way, you can suppress the error and avoid any potential issues caused by the popup not being shown while sending messages.

An alternative approach to avoid the issue of the popup not receiving messages is to display the popup in a new window using chrome.windows.create or as a DOM element within the web page. By adopting this method, the popup becomes visible and active, enabling it to receive messages as intended. This solution provides a reliable way to ensure smooth communication between the extension background script and the popup, mitigating any potential errors related to message delivery.

Background

The issue of cross-origin requests arises due to various Chrome extensions and security concerns. In order to prevent the exposure of sensitive information, web pages are typically restricted from fetching cross-origin data. Unless a valid Cross-Origin Resource Sharing (CORS) header is present on the response, the page's request will be blocked, and an error message will be displayed. This is an essential security measure that ensures data privacy and prevents unauthorized access to sensitive resources across different origins.

There was a change in Chrome that introduced this error message.

const char kReceivingEndDoesntExistError[] = // TODO(lazyboy): Test these in service worker implementation. "Could not establish connection. Receiving end does not exist."; +const char kClosedWhileResponsePendingError[] = + "A listener indicated an asynchronous response by returning true, but the " + "message channel closed before a response was received"; } // namespace

async response to runtime.sendMessage.


Example code:
// sender chrome.runtime.sendMessage('testMessage');
// receiver chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => { doSomethingWithoutResponding(msg); });
The underlying reason for this behavior is due to the internal promisification of the sendMessage function, enabling the use of 'await' functionality. Consequently, when a callback is not explicitly specified, it is automatically added internally to facilitate the return of a Promise. This, however, leads to a potential issue: if sendResponse is not invoked within onMessage, the API might mistakenly attribute the absence of a response to an oversight on the developer's part in using a callback without providing a corresponding response. As a result, the API will generate an error report to highlight this perceived mistake. To mitigate this situation, it is advisable to ensure proper handling of callbacks and responses in onMessage to align with the intended functionality of the API.

Given the perplexity experienced by most developers due to the recent change in behavior, a potential resolution could involve refraining from displaying the error when the callback is not explicitly specified. Nevertheless, this approach may create confusion for those developers who still rely on callbacks and inadvertently forget to invoke sendResponse within onMessage. It is crucial to maintain a consistent reporting system for such cases, as it has been traditionally done. A better approach may involve implementing a more nuanced solution that differentiates between intentional omission of callbacks and genuine oversights, ensuring that any lapses in handling callbacks are still appropriately reported while minimizing confusion stemming from the internal promisification process. This would provide a balanced and effective response to the issue at hand.

If you encounter these errors caused by your extension, it is advisable to thoroughly inspect all your onMessage listeners for potential issues. Specifically, focus on those listeners that lack explicit promises in their implementation. To address this, consider modifying these listeners to return promises by marking them as async functions. Doing so should suffice to resolve the problem and enable the internal promisification process to function correctly. By ensuring that all onMessage listeners return promises, your extension will align with the new behavior and successfully handle the asynchronous flow, mitigating the errors that may have arisen due to callback handling. This approach promotes a more robust and streamlined execution of your extension's functionality.

Background script

In numerous instances, the encountered issue is related to the background script's behavior. Specifically, it fails to invoke sendResponse() for one or more messages it has received and subsequently becomes inactive, leading to the closure of the message channel. Meanwhile, the content script that initiated the message is still awaiting a response, resulting in a potential communication breakdown and an unfulfilled expectation of a reply.

In Manifest V3, the Chrome extension platform transitions from using background pages to service workers. As a result, the background script, which now takes the form of a service worker, might enter an inactive state without returning a response to a message received from a content script. This change can lead to scenarios where the content script awaits a response that may not be provided, potentially disrupting the communication flow between the service worker and the content script.

Background script:
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { // ... handle message here return true // your error message says you already return true })

To listen for messages from another part of your extension, you can use the runtime.onMessage event. In Manifest V3, most APIs are asynchronous and can return promises when appropriate. Reading a response back from the message can be accomplished either by using callbacks or by employing the promise-style approach, providing developers with flexibility in handling communication between different parts of the extension.



Method-1 : Content script to read response:
chrome.runtime.sendMessage('ping', (response) => { /* read response */ })

Method-2 : Content script to read response:
chrome.runtime.sendMessage('ping').then(response => { /* read response */ })

So, in order to solve your problem, please check your message senders & handlers. Also, if you are an extension developer, You need to return true when fetching data from cross-origins.

Other solutions:

  1. Try disabled all installed extensions in Chrome then you will get a clear console without errors.

Or

  1. Go to chrome://extensions/, you can just toggle each extension one at a time and see which one is actually triggering this issue.
  2. Once you toggle the extension off, refresh the page where you are seeing the error and wiggle the mouse around, or click. Mouse actions are the things that are throwing errors.

Conclusion

Pinpointing the extension that is causing the issue and disabling it can be an effective approach to resolve 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. By selectively disabling extensions one by one, you can identify the culprit extension that is not properly handling asynchronous responses and causing the message channel to close prematurely.

Once the problematic extension is identified, you can either try updating it to handle asynchronous responses correctly or consider finding an alternative extension with similar functionality that does not produce the error. This troubleshooting method can help ensure a smooth and error-free experience for your extension users.