4

Client side errors for our app get tracked via Rollbar. We keep getting this error which is not very useful from Safari and Chrome:

[unhandledrejection] error getting `reason` from event

I traced this to Rollbar JS where it finally creates this message when it can't figure out the error inside the unhandledrejection event handler.

function captureUnhandledRejections(window, handler, shim) {
  if (!window) { return; }

  if (typeof window._rollbarURH === 'function' && window._rollbarURH.belongsToShim) {
    window.removeEventListener('unhandledrejection', window._rollbarURH);
  }

  var rejectionHandler = function (evt) {
    var reason, promise, detail;
    try {
      reason = evt.reason;
    } catch (e) {
      reason = undefined;
    }
    try {
      promise = evt.promise;
    } catch (e) {
      promise = '[unhandledrejection] error getting `promise` from event';
    }
    try {
      detail = evt.detail;
      if (!reason && detail) {
        reason = detail.reason;
        promise = detail.promise;
      }
    } catch (e) {
      // Ignore
    }
    if (!reason) {
      reason = '[unhandledrejection] error getting `reason` from event';
    }

    if (handler && handler.handleUnhandledRejection) {
      handler.handleUnhandledRejection(reason, promise);
    }
  };
  rejectionHandler.belongsToShim = shim;
  window._rollbarURH = rejectionHandler;
  window.addEventListener('unhandledrejection', rejectionHandler);
}

https://github.com/rollbar/rollbar.js/blob/a9c567cd1886f177fa4719a0054bff8280928fce/src/browser/globalSetup.js#L80-L90

Has anyone seen what this is about?

Roman
  • 10,309
  • 17
  • 66
  • 101

1 Answers1

0

This only means that a Promise that got rejected with a falsy value has been handled by this script.

var handler = {
  handleUnhandledRejection( reason, promise ) {
    console.log( reason, promise );
  }
};

var rejectionHandler = function (evt) {
  var reason, promise, detail;
  try {
    reason = evt.reason;
  } catch (e) {
    reason = undefined;
  }
  try {
    promise = evt.promise;
  } catch (e) {
    promise = '[unhandledrejection] error getting `promise` from event';
  }
  try {
    detail = evt.detail;
    if (!reason && detail) {
      reason = detail.reason;
      promise = detail.promise;
    }
  } catch (e) {
    // Ignore
  }
  if (!reason) {
    reason = '[unhandledrejection] error getting `reason` from event';
  }
  if (handler && handler.handleUnhandledRejection) {
    handler.handleUnhandledRejection(reason, promise);
  }
};
window.addEventListener('unhandledrejection', rejectionHandler);

const buttons = document.querySelectorAll("button");
buttons[ 0 ].onclick = (evt) => {
  Promise.reject(false)
};
buttons[ 1 ].onclick = (evt) => {
  Promise.reject(true)
};
<button>reject with falsey reason</button>
<button>reject with truthy reason</button>

But this handler doesn't prevent the default behavior of the event, so you should still get the default unhandled error message in the console with the correct trace to the function that did reject this Promise with a falsy reason.
If you don't have it, it means that yet something else is handling this event (and calls preventDefault()).

You could manage it by inserting at the top of your page your own handler that would call evt.stopImmediatePropagation() (note that capture doesn't help on window, you need to attach your handler before the bad one).

// before any other script runs
window.addEventListener('unhandledrejection', (evt) => evt.stopImmediatePropagation() );


// The one that would hide our trace
function badHandler(evt) {
  evt.preventDefault();
}
window.addEventListener('unhandledrejection', badHandler);


// let's make up a trace to follow
document.querySelector("button").onclick = (evt) => {
  triggerSomethingRejecting();
};
function triggerSomethingRejecting() {
  [0].forEach(() => Promise.reject(false) );
}
<button>reject</button>
<pre>
Check your browser's console to see the trace of the unhandled Promise
</pre>
Kaiido
  • 123,334
  • 13
  • 219
  • 285