12

I'm using Electrons Quick Start Projekt (Commit dbef48ee7d072a38724ecfa57601e39d36e9714e) to test exceptions.

In index.html I changed the name of the required module from renderer.js to rendererXXX.js.

require('./renderer.js')

which results in an expected Exeption (it is visible in the devtools for that window):

Uncaught Error: Cannot find module './rendererXXX.js'

Now it would be nice if the main-process (see main.js) is aware that one renderer process failed. Thus I wrapped the instatiation of the window into a try-catch-block

try {
  app.on('ready', createWindow)
} catch (e) {
  console.log("Exception caught: " + e.message);
} finally {
  // nothing yet
}

But I realized, that the Exception is not forwarded to the main-process. So what are typical ways to handle exceptions of renderer processes - is there a way to handle them from the main-process?

EDIT:

I also wrapped the line that loads the index.html into try-catch, but still I can't handle the error:

  try {
    // and load the index.html of the app.
    mainWindow.loadURL(`file://${__dirname}/index.html`)
  } catch (e) {
    console.log("Exception caught in 'createWindow': " + e.message);
  }
Edward
  • 4,453
  • 8
  • 44
  • 82
  • Try to put the try-catch inside the `createWindow` event handler function. – Bergi Aug 31 '16 at 12:39
  • @Bergi: That also did not work - I still can't see the exception in the main process. (See my updated question) – Edward Aug 31 '16 at 12:51

2 Answers2

22

Electron windows are rendered in their own process. Because of this there is little if any communication between main process and render processes. The best you can do is catch errors in the render process and use Electrons IPC module to pass them back to your main process.

In your render process:

var ipc = require('electron').ipcRenderer;
window.onerror = function(error, url, line) {
    ipc.send('errorInWindow', error);
};

In your main process:

var ipc = require('electron').ipcMain;

ipc.on('errorInWindow', function(event, data){
    console.log(data)
});

Additionally your main process can watch for a limited set of events directly on the window (or on the windows webContents):

window.on('unresponsive', function() {
    console.log('window crashed');
});

...

window.webContents.on('did-fail-load', function() {
    console.log('window failed load');
});
Max
  • 4,529
  • 1
  • 25
  • 29
  • Is there a reason for wrapping the `ipc.send` into a `window.onerror()` instead of a `try...catch`? – Edward Sep 07 '16 at 08:29
  • Well `onerror` will work for any JS error. But you can `try catch` on something specific if needed. – Max Sep 07 '16 at 08:32
  • The `window.on('unresponsive' ...` goes to the main? And is there a way to find out, by which window the IPC-message was sent? – Edward Sep 07 '16 at 09:05
  • Yes it goes in the main process. `event.sender` gives you the `webContents` of the sender window. – Max Sep 07 '16 at 09:17
  • How can I use the Webcontents-Object to close the renderer-process that has sent the IPC? I my main-process it might be the `mainWindow` or the `preferenceWindow`, ... – Edward Sep 07 '16 at 09:24
  • I dont think you can get the `window` directly from `event.sender`. The easiest thing may be to just have different names for your ipc events. Or you could loop through all of your windows and compare `window.webContents.id` with `event.sender.id`. – Max Sep 07 '16 at 09:33
  • I might be able to decide in the renderer, if the window needs to be closed. Therefore `window.close();` should work, ... – Edward Sep 07 '16 at 09:49
  • `this.state.ServerNameList.map((value,key) => )` The `vadlue` will make the react white screen as well. – Gank Nov 18 '18 at 15:03
5

I had a similar issue where I wanted to log errors to a file from the main process. Here's an addition to the answer already provided by Teak:

var ipc = require('electron').ipcRenderer;
window.onerror = function(error, url, line) {
    ipc.send('errorInWindow', error);
};

would work. Just keep in mind that the onerror callback passes 5 arguments, where the last one is the actual Error object.

https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onerror

However, since messages are serialized when sending through IPC, it's not possible to pass the Error object fully since it won't serialize correctly by default. Thus the data needs to be massaged before sending it if you need more error details (such as stack trace etc).

I used the following Is it not possible to stringify an Error using JSON.stringify? for some ideas and the end result was:

var objFromError = function(err, filter, space) {
  var plainObject = {};
  Object.getOwnPropertyNames(err).forEach(function(key) {
    plainObject[key] = err[key];
  });

  return plainObject;
};

window.onerror = function (msg, url, lineNo, columnNo, error) {
  ipcRenderer.send('asynchronous-windowerr', 'main', objFromError(error));
}

Then in main.js:

ipcMain.on('asynchronous-windowerr', function(event, source, err) {
    var str = source + ': ';

    if(err != null) {
        if(err.stack != null) {
            str += err.stack;
        } else if(err.message != null) {
            str += err.message;
        }
    }

    loggerr.appendLogFile(errLogFile, 'err', str);
})
Community
  • 1
  • 1
fredrik.j
  • 63
  • 1
  • 6