Unchecked runtime.lastError when using Chrome API

47,522

Solution 1

This error is not important in this case, but I'll explain it and how to get rid of it.

What is this error?

Chrome APIs are mostly asynchronous: you have a callback that is called when the operation completes.

In case of chrome.fileSystem.chooseEntry, the chosen entry (or entries) will be passed to a callback:

chrome.fileSystem.chooseEntry(
  {/* options */},
  function(entry) {
    // This is the callback for the API call; you can do something with entry
  }
);

However, the API is not guaranteed to yield a result. For example, as in your case, the user may refuse to provide access by clicking "Cancel". Then there is no entry to work with, and you might want some explanation as to why that happened. How to raise an error without polluting all callbacks with an extra "error" argument?

Usually, Chrome deals with this by setting a global variable, chrome.runtime.lastError, at the time the callback is called. It is uniform across Chrome async APIs to use this instead of an error argument. In fact, quoting the chrome.fileSystem docs:

All failures are notified via chrome.runtime.lastError.

  • If everything is all right, it will be undefined.
  • If there is a problem, it will be non-empty, and chrome.runtime.lastError.message will explain what's wrong.

However, some callbacks did not check for this error variable. This may indicate a programming error, and Chrome added checks that chrome.runtime.lastError is actually checked (evaluated) in a callback. If not, it considers this to be an unhandled exception, and throws this error.

Why do I say it's not important?

While it's an error, it won't break execution of your program (it's thrown at the end of an async task), and won't really be displayed to your users.

And while I say it's not important, you should check you program's logic. It may or may not be all right - this is intended to be a (stern) warning.

Why does it exist?

To warn, you, the developer, that your code probably tries to use a result that does not exist, because something went wrong.

It's possible you're already checking for an error, e.g.

if (entry) {
  // Process entry
} else {
  // Something went wrong (but what?)
}

Chrome does not employ complex heuristics to see if your code expects this possibility. As noted, errors are reported via chrome.runtime.lastError, and you're expected to check it.

Note that this error is only raised when something bad does occur, and not when the API call finishes normally.

Can I catch it?

Not really; it's not raised by your code, but the cleanup code that handles async tasks in Chrome API; therefore using try ... catch in your callback won't help. Since it's asynchronous, using try around the original API call won't help either.

What to do with it?

You should add logic to your callback that checks for problems the way Chrome expects it, and probably react to it.

function(entry) {
  if(chrome.runtime.lastError) {
    // Something went wrong
    console.warn("Whoops.. " + chrome.runtime.lastError.message);
    // Maybe explain that to the user too?
  } else {
    // No errors, you can use entry
  }
}

As long as Chrome sees that you checked the value when there is an error (that is, evaluated it within your callback), the error will not be thrown.

Solution 2

Late to the party, but here's how I suppressed the error in a chrome.windows.remove() call, in case it helps anyone else. Instead of

chrome.windows.remove(foo);  // unconditional; runtime.lastError not checked

I used

chrome.windows.remove(
        foo,
        function ignore_error() { void chrome.runtime.lastError; }
);

void evaluates its operand and then returns undefined. I think this code fairly effectively documents that its purpose is to ignore errors :) .

For brevity, ignore_error() could be pulled out of this call and used for multiple chrome API calls, or the name ignore_error could be omitted.

Update In ES6, you can use the shorter arrow function syntax:

chrome.windows.remove( foo, ()=>void chrome.runtime.lastError );

Tested in Chrome 64

Solution 3

For this type of errors try catch won't be helpful. Instead you can access the global variable chrome.runtime.lastError as @xan mentioned in his awesome response above(by the way you should read it and upvote it!).

Now, here I provide an example that can be used:

function catchLastError(){
  if(chrome.runtime.lastError){
    console.log("error: ", chrome.runtime.lastError);
  }else{
    // some code goes here.
  }
}

chrome.fileSystem.chooseEntry(yourEntry,catchLastError);
Share:
47,522
zcfrank1st
Author by

zcfrank1st

Updated on July 09, 2022

Comments

  • zcfrank1st
    zcfrank1st almost 2 years

    I use chrome.fileSystem API in my app to open a file. When I click the Cancel button of the file chooser dialog, an error occurs:

    Unchecked runtime.lastError while running fileSystem.chooseEntry: User cancelled

    How to fix this error?

  • Seti
    Seti about 9 years
    Thought so, but if he had addached the code he was using, and we saw that his callbacks do not clean the errors - we could answer it faster.
  • zcfrank1st
    zcfrank1st about 9 years
    Thank you for your reply, it's very very helpful !
  • Xan
    Xan about 9 years
    @zcfrank1st No problem. Also clarified that it's not the only way to check for errors, but a unified way across Chrome APIs.
  • joshperry
    joshperry about 9 years
    Incredible answer! Thank you for taking time to write this.
  • marlar
    marlar over 8 years
    This type of answer is why I love stackexchange :-)
  • Pacerier
    Pacerier over 7 years
    @Xan, You seem to be supporting using a global chrome.runtime.lastError instead of using an error argument for each callback. Why so? Wouldn't giving each callback its own error argument be much cleaner?
  • Xan
    Xan over 7 years
    I never said I consider this to be good architecture, but it is what it is - a design decision somewhere early in Chrome APIs. I'm not part of Chrome dev team, so I wouldn't be able to tell you why this was chosen.
  • Jordan
    Jordan about 5 years
    Uncaught TypeError: Cannot read property 'remove' of undefined
  • cxw
    cxw about 5 years
    @Jordan chrome.windows is part of the extension API. If you try to use this from a regular Web page, chrome.windows doesn't exist, giving you the error you saw.
  • jdunning
    jdunning almost 5 years
    @Xan, you say "Can I catch it? Not really", but don't address whether it can be handled by a window.onerror handler. From what I can tell, a runtime error doesn't trigger a global error handler, but I'd be happy to be proven wrong.
  • SRCP
    SRCP over 4 years
    Checking the error works, but why when I debug, lastError is undefined in the callback? It's logged to the console before the callback even runs, so when the callback runs it's undefined already. Seems to be a problem specific to debugging.