Chrome拡張機能のManifest v3で発生するようになったエラー「Uncaught (in promise) Error: Could not establish connection. Receiving end does not exist.」のお話

今回、私が作成したマウスジェスチャのChrome拡張機能 "Our Mouse Gesture"のManifestファイルをv2→v3に変更したことによって、発生するようになった謎のエラー

Uncaught (in promise) Error: Could not establish connection. Receiving end does not exist.

に関するお話です。
「エラー発生箇所がファイルの0行目ってどういうこと?」と困惑をしたのでその対応の覚え書きとなります。 f:id:holyblue:20220710192456p:plain

1. 「Uncaught (in promise) Error」は何か?

Manifest v2の時からそうだったのかもしれませんが、APIリファレンスでchrome.runtimeなどのコールバック関数を引数で指定するAPI関数の戻り値をよく見ると、"Promise"が返ってくると書いてあります。
この戻り値"Promise"は、API関数の引数でコールバック関数を指定しないときだけ返ってくる物のようです。

※chrome.runtime.sendMessageのAPIリファレンス https://developer.chrome.com/docs/extensions/reference/runtime/#method-sendMessage

f:id:holyblue:20220710193107p:plain

そして、「Uncaught (in promise) Error」のメッセージは、この戻り値の "Promise" でエラーをハンドリングしていないという意味のようでした。つまり、これまでのように以下の書き方ではこのエラーメッセージが表示されてしまうという事を意味しているのだと思います。

let message = "test";
chrome.runtime.sendmessage(message, (response)=> {
   // コールバック関数の処理
});

そのため、"Promise" でエラーをハンドリングするためには、コールバック関数を引数では指定せずに、Promise戻り値を利用する書き方への変更が求められます。

let message = "test";
let rtnPromise = chrome.runtime.sendmessage(message);
rtnPromise
   .then((response)=> {
        // コールバック関数の処理
   })
   .catch((error)=> {
        // エラー処理
   )}

こうする事で、「Uncaught (in promise) Error」というエラーの発生を抑制し、その代わりにエラーが発生したときのハンドリング処理を自分で書くことができます。

2.「Could not establish connection. Receiving end does not exist.」とは何か?

前述の通りにエラーをハンドリングすると、「Uncaught (in promise) Error」という「エラーをCatchしていませんよ。」というメッセージは出てこなくなりますが、依然として「Could not establish connection. Receiving end does not exist.」というエラーは発生しています。
ではこの「Could not establish connection. Receiving end does not exist.」はどのような時に発生するのでしょうか?

現在のところ、以下のChrome APIを実行した時にこのエラーが発生することを確認しています。

  • chrome.tabs.sendMessage()
let rtnPromise = chrome.tabs.sendMessage(tabid, message);
rtnPromise
   .then((response)=> {
        // コールバック関数の処理
   })
   .catch((error)=> {
        // エラー処理
   )}

この特定タブへメッセージを送った際に、そのタブがメッセージを受信できない状態であった場合にこのエラーが発生するようです。

2.1. エラー発生ケース1 : メッセージ送信先タブが、Chromeに関連する画面の場合

まず確実にいえることは、「chrome://」から始まるChromeが管理する画面を表示しているタブへchrome.tabs.sendMessageをした場合は確実にこのエラーが発生しました。
【例】

  • chrome://newtab/ :新しいタブ画面
  • chrome://extensions/ :Chrome拡張機能管理画面

そのため、対策としてはメッセージ送信先タブのURLがChromeが管理する画面の場合は、メッセージを送信しない様に制御することが考えられます。
ただ、「chrome://」から始まるURLで判別すると、Chromium Edgeに対応できないので、「http」から始まるURLの時にメッセージを送信するという判別にした方がよいと思われます。

2023/05/04追記
Chrome Webストアのページでもこのエラーが発生する事が確認されたので追記をしておきます。
- URL:https://chrome.google.com/webstore

2.2. エラー発生ケース2 : Content Scriptがメッセージを受け取れない状態(固まっている?)の場合

2つ目のケースは純粋にメッセージを受け取る側のタブのContent Scriptに何かしらの問題が発生していて、chrome.tabs.sendMessageで送られてくるメッセージを受信できない状態のときのようでした。 このエラーが発生したタブでは、私が作成したMouse Gestureが正常に動作しなくなっていたので、そこから Content Script に問題が発生しているのでは無いかと推測しました。

後書き

現時点(2022/07/11)で分かっている事を纏めてみました。
同様の問題に直面している人の助けになれたら幸いです。
最後まで読んで頂きありがとうございました。