3

chrome.browserAction.setBadgeText(object details) is used to set the badge text for a chrome extension. However, if the tabId doesn't exist, Chrome produces the following error using console.error():

Unchecked runtime.lastError while running browserAction.setBadgeText: No tab with id: ####.

This becomes a problem when the badge text is set during a page load. If the tab originally exists but is closed by the user, setBadgeText ends up being called using a non-existent tabId.

Normally, this can just be prevented by checking chrome.runtime.lastError in the callback argument of the problematic function as was answered in another question. However, since browserAction.setBadgeText() has no callback parameter, there seems to be no way to prevent the error.

When tabId is an integer not representing any tab, the following code still produces the error even though it attempts to...

  • catch the error with try...catch (which doesn't work since console.error() is not thrown).
  • check lastError after calling setBadgeText (which doesn't work since the function is asynchronous).
  • use various setTimeout intervals to check lastError after calling setBadgeText (which doesn't work and probably wouldn't be reliable).
  • add a callback argument to setBadgeText (which has been commented out since chrome produces another error when using it since there is no second argument).
var tabId = 5000;
function clearError () {
    console.log(chrome.runtime.lastError);
}
try {
    chrome.browserAction.setBadgeText({
        text: 'text',
        tabId: tabId
    }/*, clearError*/);
    clearError();
    setTimeout(clearError, 0);
    setTimeout(clearError, 50);
    setTimeout(clearError, 500);
}
catch (e) {
    console.log('Caught', e);
    clearError();
}

Would there be any way to properly check chrome.runtime.lastError to prevent this error from occurring?

Community
  • 1
  • 1
Anonymous
  • 11,748
  • 6
  • 35
  • 57
  • 2
    This actually seems to be a bug in Chrome (the fact that `lastError` assumes that a callback exists, but the signature does not allow for it). You should report it. – Xan Aug 21 '15 at 11:13
  • ..and if you do report it, you should link to the issue here. – Xan Aug 24 '15 at 15:25
  • Did they solve this bug yet? There needs to be a handler for setBadgeText if it's gonna set lastError! – Pacerier Aug 10 '17 at 03:47
  • @Xan, On the other hand, isn't there a way to hook into the "global" error handler for the Chrome extension? – Pacerier Aug 10 '17 at 03:48
  • Hooking https://stackoverflow.com/questions/16571393/the-best-way-to-check-if-tab-with-exact-id-exists-in-chrome/25831100#comment27755699_16572307 – Pacerier Aug 10 '17 at 04:10
  • @Pacerier No they didn't. Thanks for the reminder though. I meant to post an answer with the bug report. – Anonymous Aug 10 '17 at 15:08
  • 1
    Note that starting with Chrome 67 you should be able to use a callback to catch errors. At least this was the reply I got after [reporting this issue](https://groups.google.com/a/chromium.org/forum/#!msg/chromium-extensions/nAk_Hlkv46o/4UiwZkcmCAAJ). – thdoan Apr 27 '18 at 05:34

3 Answers3

6

An option would be to call chrome.tabs.get first and if no error is called assume that the tab will exist for the next few milliseconds.

var tabId = 5000;
function callback(tab) {
    if (chrome.runtime.lastError) {
        console.log(chrome.runtime.lastError.message);
    } else {
        chrome.browserAction.setBadgeText({
            text: 'text',
            tabId: tabId
        });
    }
}
chrome.tabs.get(tabId, callback);

There is of course always a chance the tab could get closed between tabs.get finishing and setBadgeText getting called but it's very unlikely.

abraham
  • 46,583
  • 10
  • 100
  • 152
1

In addition to chrome.tabs.get() as described above, you can also piggyback off an existing browserAction method that accepts a callback to catch for errors. Example:

var tabId = 5000;
chrome.browserAction.getTitle({tabId: tabId}, function(result) {
  if (chrome.runtime.lastError) return;
  // The coast is clear...
  chrome.browserAction.setBadgeText({
    text: 'text',
    tabId: tabId
  });
});

Good news: chrome.browserAction.setBadgeText() should also support a callback function like chrome.browserAction.getTitle() starting with Chrome 67 according to one source. Fingers crossed!

thdoan
  • 18,421
  • 1
  • 62
  • 57
0

A bug was reported for this issue and has been marked as fixed: https://crbug.com/451320

Anonymous
  • 11,748
  • 6
  • 35
  • 57