contextBridge.exposeInMainWorld does not copy Error details · Issue #25596 · electron/electron · GitHub
Skip to content

contextBridge.exposeInMainWorld does not copy Error details #25596

Closed as not planned

Description

@rfricz

Preflight Checklist

  • I have read the Contributing Guidelines for this project.
  • I agree to follow the Code of Conduct that this project adheres to.
  • I have searched the issue tracker for an issue that matches the one I want to file, without success.

Issue Details

When calling functions exposed by contextBridge.exposeInMainWorld, Promises rejected with Error objects or directly thrown Errors (and even caught Errors returned in a wrapper) are not copied as the documentation states – all important information except the message is removed, e.g. Common System Error properties like err.code, err.path etc. are gone. Also, the “Uncaught Error: ” message prefix is not very helpful.

  • Electron Version:
    • 10.1.2
  • Operating System:
    • Windows 10 (2004)

Expected Behavior

Instances of the Error class (or inherited from it) coming from the context bridge should have all properties preserved (except err.stack, obviously) and message left intact to allow meaningful error handling. Structured Clone Algorithm otherwise serializes Error objects correctly.

Actual Behavior

The Error object is stripped of important additional properties and has a confusing message saying it’s uncaught even when caught on both sides of the bridge.

To Reproduce

preload.js

const { contextBridge } = require('electron');
const fs = require('fs');

contextBridge.exposeInMainWorld('myapi', {
  request: () => fs.lstatSync('foo')
});

renderer

try {
  window.myapi.request();
} catch (e) {
  console.dir(e);
}

Activity

  1. MarshallOfSound commented on Sep 28, 2020

    @MarshallOfSound
    Member

    @richardfritsch We follow the same strategy for cross-boundarysanitization as chrome. If you try and dispatchEvent with a custom Event object with custom properties those properties will be lost when accessing that event in another world. Errors are tricky because we as a framework don't know what could be in the custom properties on Error objects and don't want to let users shoot themselves in the foot by setting custom properties on error objects that then get leaked into the main world.

    IMO in your case of fs usage the renderer should never know why the request failed, just that for some reason it did. Passing details like error code and in particular the filesystem path is counter to the goals of isolated the untrusted renderer from that kind of information.

  2. rfricz commented on Sep 29, 2020

    @rfricz
    Author

    Thanks for having a look at it. In my case, knowing why a request failed is needed - the app works with files, folders and lockfiles often located on shared network drives etc. where permission and accessibility errors occur – the app will retry or inform the user based on the error details. I understand the security concerns, it’d just be nice if I didn’t have to restructure the code to return the error details inside a plain object and could just catch an exception instead. An option for exposeInMainWorld to allow Errors to pass would be handy.

  3. CherryDT commented on Jan 4, 2021

    @CherryDT

    I ran into the same problem, errors convey meaning here, including their extra properties (and I'm using instanceof on errors as well). And of course a stack would be nice...

    It would be great if this could be the choice of the developer, yes.

    In this particular case, I'm using the preload code as sort of a "middleware" which, if existing (i.e., app is run inside Electron and not browser) is called by the frontend with a callback, so the middleware can intercept or inject functionality if required. But, if the inner code (passed as callback) is throwing a certain error, it's expected to stay that error.

    Frontend code:

    class SomeSpecialError extends Error {}
    
    const middleware = window.electron ? window.electron.middleware : (fn => fn())
    
    try {
      await middleware(async function () {
        throw new SomeSpecialError()
      })
    } catch (e) {
      if (e instanceof SomeSpecialError) {
        console.log('works')
      } else {
        console.log(':-(')
      }
    }

    Preload code:

    const { contextBridge } = require('electron')
    
    contextBridge.exposeToMainWorld('electron', {
      middleware: async fn => {
        return await fn()
      }
    })

    Result is :-( if run with window.electron existing, otherwise works. I'd like it to be works in both cases.

    In fact, this example is simplified: I'm actually passing SomeSpecialError into the middleware too, so that if the middleware inside Electron wants to throw it, it can do that too - not only the callback inside the frontend code can. (Which of course doesn't work right now.)

  4. mifi commented on Jan 19, 2022

    @mifi
    Contributor

    Somewhat related #24427

  5. github-actions commented on Oct 7, 2022

    @github-actions
    Contributor

    This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. If you have any new additional information—in particular, if this is still reproducible in the latest version of Electron or in the beta—please include it with your comment!

  6. mifi commented on Oct 7, 2022

    @mifi
    Contributor

    stil an issue

  7. github-actions commented on Jan 24, 2023

    @github-actions
    Contributor

    This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. If you have any new additional information—in particular, if this is still reproducible in the latest version of Electron or in the beta—please include it with your comment!

  8. mifi commented on Jan 24, 2023

    @mifi
    Contributor

    Would you be open for a PR of at least removing the «Unchaught error: » prefix? Or maybe also copying simple Primitive props?

  9. 20 remaining items

  10. clemp6r commented on Oct 11, 2024

    @clemp6r

    bump

  11. WorkAttackDev commented on Oct 18, 2024

    @WorkAttackDev

    bump

  12. electron-issue-triage commented on Jan 19, 2025

    @electron-issue-triage

    This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. If you have any new additional information—in particular, if this is still reproducible in the latest version of Electron or in the beta—please include it with your comment!

  13. clemp6r commented on Jan 20, 2025

    @clemp6r

    bump

  14. electron-issue-triage commented on Apr 21, 2025

    @electron-issue-triage

    This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. If you have any new additional information—in particular, if this is still reproducible in the latest version of Electron or in the beta—please include it with your comment!

  15. clemp6r commented on Apr 22, 2025

    @clemp6r

    bump

  16. electron-issue-triage commented on Jul 22, 2025

    @electron-issue-triage

    This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. If you have any new additional information—in particular, if this is still reproducible in the latest version of Electron or in the beta—please include it with your comment!

  17. electron-issue-triage commented on Aug 22, 2025

    @electron-issue-triage

    This issue has been closed due to inactivity, and will not be monitored. If this is a bug and you can reproduce this issue on a supported version of Electron please open a new issue and include instructions for reproducing the issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions