webextension-polyfill: Can't send runtime messages in Firefox; Error: "TypeError: promise.then is not a function"

I’m getting the following error in Firefox when I try to send a runtime message from a content script to a background script:

Unhandled promise rejection 
TypeError​columnNumber: 9​
fileName: "resource://gre/modules/ExtensionCommon.jsm"​
lineNumber: 490​
message: "promise.then is not a function"
​stack: "wrapPromise/<@resource://gre/modules/ExtensionCommon.jsm:490:9_@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:69770
wrapPromise@resource://gre/modules/ExtensionCommon.jsm:489:14
callAsyncFunction@resource://gre/modules/ExtensionCommon.jsm:697:12
stub@resource://gre/modules/Schemas.jsm:2297:22
t/<@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:96454
b@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:50347
A/o._invoke@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:50137
E/</t[n]@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:50523
e@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:96739
i/<@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:96722
_@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:69770
i@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:96680
u<@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:96912
@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:96983
r@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:105
@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:97021
r@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:105
@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:517
@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:2
inject@resource://gre/modules/ExtensionContent.jsm:483:18
injectInto@resource://gre/modules/ExtensionContent.jsm:388:14
"​__proto__: Object { stack: "", … } content_script.js:1:69061
// content_script.js

import browser from "webextension-polyfill";

async function sendMessage() {
  const { response } = await browser.runtime.sendMessage({
    kind: "LOREM",
    data: "ipsum"
  });

  console.log("content_script: response:", response);
}

sendMessage();
// background_page.js

import browser from "webextension-polyfill";

browser.runtime.onMessage.addListener(async ({ kind, data }) => {
  if (kind === "LOREM") {
    return Promise.resolve({ response: data });
  }

  return false;
});

I’m using webpack with babel-polyfill to include the generator runtime:


module.exports = {
  entry: {
    background_page: ["babel-polyfill", "./src/background_page.js"],
    content_script: ["babel-polyfill", "./src/content_script.js"]
  },

  output: {
    path: path.resolve(__dirname + "/dist"),
    filename: "[name].js"
  },

  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ["babel-preset-env"]
          }
        }
      }
    ],
  }
}

It works fine in Chrome. What am I missing?

About this issue

  • Original URL
  • State: open
  • Created 6 years ago
  • Reactions: 1
  • Comments: 18 (7 by maintainers)

Commits related to this issue

Most upvoted comments

@Rob--W I was also facing similar issue in Firefox. browser.runtime.onMessage.addListener should be waiting for the Promise to resolve and the return to the browser.runtime.sendMessage. It worked in Chrome but in Firefox it returned and didn’t wait. I was using babel-polyfill. Following your solution helped and now the extension works as expected in all the browsers. Thank you. 👍

https://github.com/abhijithvijayan/kuttUrl-browser-extension/commit/7564e7ecfd2bd203270544519e993151c891527f

Closing this since this is not an issue with the polyfill, but with Firefox * as explained in https://github.com/mozilla/webextension-polyfill/issues/105#issuecomment-383990462 . The solution is also described in the previous comments: change the webpack/babel configuration to not replace the Promise global.

* The polyfill is a no-op in Firefox. We will document this more clearly and close #55 in the future.

I got it working by changing my webpack setup to use “babel-preset-env” with my current node as the target so that it uses native async/await.

Thanks @Rob--W for the help!

My updated webpack config for completeness:

const path = require("path");
module.exports = {
  entry: {
    background_page: ["./src/background_page.js"],
    content_script: ["./src/content_script.js"]
  },

  output: {
    path: path.resolve(__dirname + "/dist"),
    filename: "[name].js"
  },

  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: "babel-loader",
          options: {
            presets: [["babel-preset-env", { targets: { node: "current" } }]]
          }
        }
      }
    ]
  }
};

@Rob--W Thanks for pointing that out.

I fixed my problems by removing babel-polyfill and adding babel-plugin-transform-runtime with the polyfill option set to false.

.babelrc

{
    ...
    "plugins": [
        ...
        [
            "transform-runtime",
            {
                "polyfill": false,
                "regenerator": true
            }
        ]
    ]
}

@rikedia In your extension, the native Promise constructor has been replaced with something else. Don’t do that (e.g. by removing babel-polyfill; both Chrome and Firefox support async / await these days).

The fact that replacing the global Promise constructor breaks sendMessage is probably an unintended bug. I have reported it upstream at https://bugzilla.mozilla.org/show_bug.cgi?id=1456531 .

Can you share your generated bundle?

Side note, the following is incorrect if your intent is to only respond to LOREM because the onMessage handler is an async function, which returns a promise by default.

browser.runtime.onMessage.addListener(async ({ kind, data }) => {
  if (kind === "LOREM") {
    return Promise.resolve({ response: data });
  }

  return false;
});

should be without async, or simply:


browser.runtime.onMessage.addListener(async ({ kind, data }) => {
  if (kind === "LOREM") {
    return { response: data };
  }
});