asynchronous-javascript

Chrome.runtime.onMessage returns "undefined" even when value is known for asynchronous response


In my code I have a content script which requests a cookie from the background script.

Even though I can print the cookie to the Dev Tool console, the message received from background script is always undefined.

Why?

Background script:

// listens for content scripts to request the cookie 
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
        // Respond with the value of the cookie 
        if (message === 'get-cookie') {
            chrome.cookies.get({"url": "http://www.example.com", "name": "cookie_example"}, function(cookie) {
                // prints the correct value
                console.log(cookie.value);
                sendResponse(cookie.value);
                });
             }
      });
   }
});

Content script:

chrome.runtime.sendMessage('get-cookie', (response) => {
    // logs "undefined"
    console.log(response);
    /* tries to do something useful with the response */
});

And returns an error

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

Solution

  • This happens because getting the cookie is an asynchronous action. As per documentation the onMessage returns boolean or undefined. Since no boolean is returned, the onMessage returns undefined and fails with the error.

    To solve the problem, you must return a boolean value true to indicate the onMessage is returning an asynchronous response. Remember to place such return at the very end of your code, outside any asynchronous requests. Anything below such return will be ignored.

    Note: Returning a Promise will NOT work.

    Fixed code:

    Background script:

    // listens for content scripts to request the cookie 
    chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
            // Respond with the value of the cookie 
            if (message === 'get-cookie') {
                chrome.cookies.get({"url": "http://www.example.com", "name": "cookie_example"}, function(cookie) {
                    // prints the correct value
                    console.log(cookie.value);
                    // will send the correct value in due time
                    sendResponse(cookie.value);
                    });
                 }
          });
    
         
         return true; // CRUCIAL! indicates that an asynchronous response is being processed
    
         /* anything here will be ignored */
    
       }
    });
    

    Content script:

    chrome.runtime.sendMessage('get-cookie', (response) => {]
        // logs the correct value
        console.log(response);
        /* can successfully do useful things with the response */
    });