23

I'm coding my Google Chrome Extension where I set the app's icon from the background script as such:

try
{
    objIcon = {
        "19": "images/icon19.png",
        "38": "images/icon38.png"
    };

    chrome.browserAction.setIcon({
        path: objIcon,
        tabId: nTabID

    });
}
catch(e)
{
}

Note that I wrapped the call in try/catch block.

Still, sometimes I'm getting the following message in the console log:

Unchecked runtime.lastError while running browserAction.setIcon: No tab with id: 11618.

It's hard to debug this error because it seems to come up only when I close or reload the Chrome tab, it doesn't have a line number or any info for me to track, plus it's not easy to run through a debugger (i.e. I cannot set a break-point on the moment when error occurs, but if I blindly set a break-point on the chrome.browserAction.setIcon() line, I don't see the message in the log anymore.)

So I'm curious if anyone could suggest how to remedy this error?

EDIT: Just to post an update. I am still unable to resolve this issue. The suggestion proposed by @abraham below offers a somewhat working approach, but it is not fail safe. For instance, in a situation when the tab is closing I may call his suggested chrome.browserAction.setIcon() that may succeed if the tab is not yet closed, but while within its callback function the tab may eventually close and thus any consecutive calls to some other API that requires that same tab ID, say setBadgeBackgroundColor() may still give me that same No tab with id exception. In other words, for those who know native programming, this is a classic race condition situation. And I'm not sure if it's a bug in Chrome, because obviously JS does not offer any thread synchronization methods...

I've witnessed this behavior several times while doing my tests. It doesn't happen often because we're talking about very precise timing situation, but it does happen. So if anyone finds a solution, please post it below.

c00000fd
  • 20,994
  • 29
  • 177
  • 400
  • Could you show us how you determine `nTabID`? – Teepeemm Sep 09 '14 at 01:25
  • @Teepeemm: I can't. It may come from many places. For instance, from `sender.tab.id` in `chrome.runtime.onMessage.addListener`, or from `chrome.tabs.query({active: true, currentWindow: true}` – c00000fd Sep 09 '14 at 01:44
  • I might have found a solution to check if tab ID exists: http://stackoverflow.com/a/25831100/843732 – c00000fd Oct 08 '14 at 20:25
  • possible duplicate of [The best way to check if Tab with exact ID exists in Chrome](http://stackoverflow.com/questions/16571393/the-best-way-to-check-if-tab-with-exact-id-exists-in-chrome) – Teepeemm Jun 19 '15 at 19:48
  • If you want to stop the error, see https://stackoverflow.com/a/45603880/632951 – Pacerier Aug 10 '17 at 03:31

2 Answers2

25

Include a callback and check chrome.runtime.lastError.

objIcon = {
    "19": "images/icon19.png",
    "38": "images/icon38.png"
};

function callback() {
    if (chrome.runtime.lastError) {
        console.log(chrome.runtime.lastError.message);
    } else {
        // Tab exists
    }
}

chrome.browserAction.setIcon({
    path: objIcon,
    tabId: nTabID

}, callback);
abraham
  • 46,583
  • 10
  • 100
  • 152
  • Thanks for suggestion. I just got `No tab with id: 12360.` as `lastError.message`. I don't understand how can that happen when I get tab ID from one of the `chrome` functions? – c00000fd Sep 09 '14 at 06:52
  • There are any number of ways a tabId can become invalid. The most common is the tab has been closed. – abraham Sep 09 '14 at 12:24
  • 2
    So I got this exception "muted out" by using your method, but what shall I do with `chrome.browserAction.setBadgeText()` and `chrome.browserAction.setBadgeBackgroundColor()`? – c00000fd Sep 11 '14 at 05:36
  • 1
    Put them in the callback to run if `chrome.runtime.lastError` is false. – abraham Sep 11 '14 at 12:51
  • 2
    Do `setBadgeText` and `setBadgeBackgroundColor` have callbacks? – c00000fd Sep 11 '14 at 17:16
  • 3
    I'm sorry, I'm not following your drift. `browserAction.setBadgeBackgroundColor(object details)` does not have any callbacks. Is that what you meant? – c00000fd Sep 11 '14 at 19:39
  • You asked if the APIs had a feature and I linked to the documentation that describes the functionality of the methods. – abraham Sep 11 '14 at 21:49
  • 1
    OK. I guess I did not understand how I would implement this: `Put them in the callback to run if chrome.runtime.lastError is false` – c00000fd Sep 11 '14 at 22:20
  • 1
    Oh, I get it now. You wanted me to put `setBadgeText` and `setBadgeBackgroundColor` into the callback for `chrome.browserAction.setIcon`. Sorry, I didn't understand you. It's a good idea, let me try. – c00000fd Sep 12 '14 at 03:38
  • @c00000fd if this was the correct solution please accept the answer. – abraham Sep 16 '15 at 14:07
  • As my edit to the OP explains, your suggestion works but it is not a complete solution. – c00000fd Sep 16 '15 at 21:10
  • @c00000fd, That there are no callbacks is a fking Chrome bug. See https://stackoverflow.com/a/32132554/632951 for a stopgap fix. – Pacerier Aug 10 '17 at 04:06
  • How would you do this for `chrome.browserAction.setBadgeText()` which doesn't accept callbacks? – thdoan Apr 17 '18 at 22:01
0

The below works for me

/** 
 * Update icon, text and background
 * Handle the case where the tab_id no longer exists
 */
function updateIconAndBadge(tab_id, icon_path, badge_text, badge_background_color) {

    // Set the icon path
    chrome.browserAction.setIcon({ path: icon_path, tabId: tab_id },
        // Call back
        () => {
            // Check for error
            if (chrome.runtime.lastError) {
                // Failed - tab is gone
                console.log(`Tab ${tab_id} no longer exists.`);
            }
            else {

                // Ok - Set the badge text 
                chrome.browserAction.setBadgeText({
                    tabId: tab_id,
                    text: badge_text
                });

                // Set the back ground colour
                chrome.browserAction.setBadgeBackgroundColor({
                    tabId: tab_id,
                    color: badge_background_color
                });
            }
        });
}