Do contextMenus methods really have Promise support ?

153 views
Skip to first unread message

Max Nikulin

unread,
Oct 3, 2024, 6:53:08 AMOct 3
to chromium-...@chromium.org
Hi,

I have puzzled by the following results:

await chrome.contextMenus.update(13, { title: "Non-existing"})
Unchecked runtime.lastError: Cannot find menu item with id 13
undefined

await chrome.contextMenus.remove(13)
Unchecked runtime.lastError: Cannot find menu item with id 13
undefined

Is there a reason why these functions do not return *rejected* Promise
objects? I see no point in insisting on callbacks for error handling.

This behavior is observed in Chromium-129, Linux.

Accordingly to
<https://developer.chrome.com/docs/extensions/whats-new#chrome_122_promise_support_on_asynchronous_extension_apis>
> Chrome 122: Promise support on asynchronous extension APIs
>
> Posted on February 22, 2024
>
> We've finished implementing Promise support for all asynchronous
> extension API methods.

I admit that `contextMenus.create` does not throw exceptions even for
errors that can be detected synchronously to not break (buggy?) existing
extensions

await chrome.contextMenus.create({ onclick: () => null })
12
Unchecked runtime.lastError: Extensions using event pages or
Service Workers must pass an id parameter to chrome.contextMenus.create

(Side note: 12 is not "The ID of the newly created item."
<https://developer.chrome.com/docs/extensions/reference/api/contextMenus#method-create>
since no item created.)

I have not found a task related to Promise support in the issue tracker
to check if behavior is intentional.

Have I missed a case when promises are not enough to report exceptions
thrown by `remove` or `update` calls?

woxxom

unread,
Oct 4, 2024, 2:28:12 AMOct 4
to Chromium Extensions, Max Nikulin
It is indeed incompletely promisifed, see https://crbug.com/40154924 and the API definition in the source code, which is yet another known bug in MV3 that's not being fixed even though MV2 is already getting disabled.
  • chrome.contextMenus.create returns an id synchronously, which is how it was designed back in the day. Judging by the bug report it wasn't promisified in order not to break the existing extensions, but I'd say go ahead and break it, because MV3 doesn't have a persistent background script by design, meaning we can't use the synchronous form of create() to obtain an id anyway, we have to specify it explicitly like create({id: ...}). Firefox developer Rob Wu says as much in https://crbug.com/40154924.

  • chrome.contextMenus.update() and remove() return a Promise in MV3 and you'll see it if you remove "await", but .catch() on this promise doesn't work, meaning the API is promisified incorrectly. You can report it in https://crbug.com. Meanwhile either use a callback and promisify it yourself or simply check chrome.runtime.lastError explicitly after "await".

Max Nikulin

unread,
Oct 8, 2024, 8:02:25 AMOct 8
to chromium-...@chromium.org
On 04/10/2024 13:28, woxxom wrote:
> It is indeed incompletely promisifed, see https://crbug.com/40154924 and
> the API definition in the source code
> <https://crsrc.org/chrome/common/extensions/api/context_menus.json;l=206;drc=218bd5b76c310d025dc4d9dff6feb4a799117a45>,
> which is yet another known bug in MV3 that's not being fixed even
> though MV2 is already getting disabled.

Return value of contextMenus.create is an excuse to some extent that it
is not converted to Promise. However I do not like discrepancy with
Firefox what exceptions are thrown synchronously. Subtle differences are
not friendly to feature detection code like in
<https://extensionworkshop.com/documentation/develop/manifest-v3-migration-guide/#event-driven-background-scripts>

Perhaps adding a new method is better than modifying `create`
<https://github.com/w3c/webextensions/issues/312>
"[contextMenus] create or update contextMenus in a single call"
For simple cases (extension update) docs should clearly suggest
`contextMenus.removeAll()` and recreate items from scratch.

> * chrome.contextMenus.update() and remove() return a Promise in MV3
> and you'll see it if you remove "await", but .catch() on this
> promise doesn't work, meaning the API is promisified incorrectly.
> You can report it in https://crbug.com. Meanwhile either use a
> callback and promisify it yourself or simply check
> chrome.runtime.lastError explicitly after "await".

I have noticed that `update` does not reject promises after I decided
that I can drop promisify polyfill in mv3. It is disappointing (C++ has
std::broken_promise...).

To be fair, I have not managed to get error in any form (exception,
rejected promise, runtime.lastError) from `update` and `remove` in
Firefox 115 ESR and 128 ESR. I have tried `browser` and `chrome`,
`contextMenus` and `menus`.

Actual reason why I had `contextMenus.update` is that I noticed warnings
concerning missed runtime.onInstalled event in some obscure cases
related to update in disabled state or incognito windows. Perhaps it has
been fixed. So expectation was that `update` error means wiped menu
entries. A workaround appeared to be more fragile.

Behavior of `tabs` methods is correct from my point of view

chrome.tabs.reload(123).catch(ex => console.log("ex async", ex))
Promise {<pending>}
ex async Error: No tab with id: 123.
chrome.contextMenus.remove(123).catch(ex => console.log("ex async", ex))
Promise {<pending>}
Unchecked runtime.lastError: Cannot find menu item with id 123

At first glance error handling is similar
<https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/extensions/api/tabs/tabs_api.cc;l=1907>
<https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/extensions/api/context_menus/context_menus_api.cc;l=88>

As to filing a bug, I hate pressure to provide a video for an issue that
may be described with a dozen of lines of text. In addition, I suspected
that I missed some reason why `contextMenus.update` and `remove`
promises are not rejected.

woxxom

unread,
Oct 8, 2024, 9:50:20 AMOct 8
to Chromium Extensions, Max Nikulin
There's no need to provide a video. It'll be added by the triage team after they reproduced your description.
Reply all
Reply to author
Forward
0 new messages