Errors not shown - How to workaround non-existent `onunhandledrejection`

If there is error in async function UXP won’t tell you it.

So you have wrap into try/catch every single async function in your plugin and rethrow that explicitly otherwise you will have no idea about an error.

Also I want to integrate Sentry.

I can add Sentry for Browser. I can also explicitly send an error calling sentry function and it works. But it does not catch unhadled rejections automatically. Because onunhandledrejection is not implemented in UXP.

Sentry listents to that event but UXP will never fire it. Also unhandled rejection is never logged into console by default. I have to use try/catch and rethrow it myslef.

Is there some a way to workaround it? I was thinking maybe to intercept Error constructor or something like that but it did not work. And Error.captureStackTrace is called in so many non-error cases that I cannot use it.

I can wrap top level code into try/catch call Sentry explicitly and it works for awaited child functions but if some nested promise is not awaited then it is not catched and error not reported.

7 Likes

+1 For this issue. We really need better errors in UXP for debugging and error reporting with systems like Sentry.

1 Like

I third this motion.

Agreed. Gets cumbersome and error prone to manage potential for rejected promises with things like button handlers.

I asked Sentry for workaround. They don’t see any good one. How to workaround non-existent `onunhandledrejection` in Adobe UXP (Javascript) · getsentry/sentry-javascript · Discussion #12338 · GitHub

I also agree. I have Sentry integrated into one of my plugins, but I am wrapping the code in try/catch as you mentioned. I only added it to parts which I think are critical but it’s cumbersome and I may miss errors.

1 Like

This works in Chrome but I can’t make it work in UXP GitHub - rtsao/browser-unhandled-rejection: A ponyfill/polyfill for browser Promise unhandledrejection events

Can anyone figure out why?

Yes please. Log uncaught errors in promises.

Any updates on this? This is one of the big reasons why devs run away from UXP to something less painful. @indranil @Sujai

Related:

Unrelated but still issue:

1 Like

+1 for this issue, im trying to migrate to UXP but the error handling in painful.

1 Like

Any updates? Please this is important. This is one of the big reasons why devs run away from UXP. They just can’t see their errors without workarounds. @indranil @Erin_Finnegan @samgannaway @mykim @Ingo @pkrishna @DavideBarranca

1 Like

I know you are very busy doing all that Adobe Express stuff… and those who are still in UXP team have a lot of work…

but if this is not going to be addressed… Should I quit with UXP and change my job? Perhaps AI? I have big code base. There are going to be thousands of async/await. Should I wrap every single of them? Or how do you imagine error handling? I need reliable plugins. If I can’t do that… there is no point developing them.

@indranil @Erin_Finnegan @samgannaway @mykim @Ingo @pkrishna @DavideBarranca

1 Like

Yeah, I stopped using UXP due to this and inadequate CSS.
Life’s definitely less stressful without it.

Ok, I’m trying to get back to this. Do you have a simple example I can use to demo for others? I know the situation, but I want to be consistent with what will help first/most/best and what we fix.

1 Like

Try this:

window.onerror = function (msg, url, lineNo, columnNo, error) {
	console.log('error', error);
};
window.onunhandledrejection = function (e) {
	console.log('unhandledrejection', e.reason);
};
window.addEventListener('error', function (e) {
	console.log('error', e.error);
});
window.addEventListener('unhandledrejection', function (e) {
	console.log('unhandledrejection', e.reason);
});

async function abc() {
	window.thisDoesNotExistAAA();
}

async function xyz() {
	try {
		window.thisDoesNotExistBBB();
	} catch (e) {
		throw e;
	}
}

var core = require("photoshop").core;

var execAbc = core.executeAsModal(async () => {
	await abc();
}, {commandName: "abc"});

var execXyz = core.executeAsModal(async () => {
	await xyz();
}, {commandName: "xyz"});

Promise.allSettled([
	abc(),
	xyz(),
	execAbc,
	execXyz,
]).then((res) => {
	//console.log(res);
	console.log('done... did you turned on "pause on exceptions in UDT"? How many times did it throw? 2? 4?');
	console.log("did console said anything about error?");
});

It gets much worse in executeAsModal

Run it from plugin. Not from UDT console.

2 Likes

Definitely CSS should work too! And it’s not for beauty only (but beauty it’s also important). For example, I need to use the ‘box shadow’ as a mask when cropping on the panel. But ‘box shadow’ doesn’t work. And there’s a lot of that.

I was unhappy with CEP at the time. Forgive me CEP, you’re great. “Make a person feel bad, then as it was, and the person will be happy” (с)

I understand that UXP is not a browser , box shadow is already available in PS version 26, however, they have not yet added some of the main properties to CSS, it is really frustrating not being able to apply a simple opacity: 0.5, to simulate a “disabeled=true” in a div containing several child elements. Please UXP team, in the next update, add the 100% functional “opacity” property.

The UXP team says opacity is implemented in UXP but not implemented/rendered in Photoshop. (maybe it works e.g. in XD?). However, please move CSS discussions to the proper topic.

I am trying to focus on error handling here to get it done :smiley:

2 Likes

It would be a garganutan loss to the entire ecosystem if prolific UXP developers such as you, who are paragons of community engagement, abandoned UXP. We’ve been aware of this issue (you and I’ve also discussed the onerror issue on similar lines). Here’s why we’re inhibited by the available APIs and can’t support this in UXP.

V8, the underlying UXP Javascript engine does provide a way to hook up callbacks for figuring out unhandled promise rejections via setPromiseRejectCallback() but UXP in Photoshop(or InDesign) doesn’t use V8 directly but via an ABI-stable (which is of paramount importance in the world of C++) API surface called Node-API. This API interface provides no such avenues to register any callback with V8. This prevents UXP from being able to handle your exact requirements. It’s not the answer that you were probably expecting but unless Node-API allows such APIs or allows accessing the underlying V8 isolate in a safe well-defined manner, this stands, as of today, as a limitation of the UXP platform.

Since you did mention AI, instead of switching over to it, I could hazard a suggestion of having it write the (yes I know!) ugly try-catch blocks or you could try refactoring your code to handle errors with utility functions as something on the lines of

const handleError = fn => async (...params) => {
  try {
    await fn(...params);
  } catch (error) {
    console.error('Error:', error);
  }
};

and then if you have some code like

const riskyOperation = async (throwError) => {
  if (throwError) {
    throw new Error('Oops!');
  } else {
    console.log('Operation succeeded!');
  }
};

you could wrap all such calls into

doOperation = handleError(riskyOperation);

and then call into them

doOperation(true);  // This *will* log an error
doOperation(false); // This will log 'Operation succeeded!'

Obviously not an ideal solution and I can’t think of all possible issues with such an approach but given large codebases, this could possibly alleviate the pain of wrapping every promise in a try-catch block. I don’t think anything is palatable but given what UXP is, one needs to operate within the constraints of the architecture of the system.

2 Likes