#Exception Notifications

1 messages · Page 1 of 1 (latest)

brittle gate
#

Just want to extract the essence here: We're looking for a way for core foundry to notify modules when it encounters an error that it would otherwise catch, log, and continue?

atomic briar
#

yeah, exactly.

#

Basically, we want a way to be notified that there's an error that Foundry doesn't know what to do with (and would just log and ignore). For example, because we want to notify the user explicitly, log it ourselves, etc.

warm helm
#

Right now (to the best of my understanding at least) Foundry finds these errors and probably logs and ignores them, but they don't appear in the console (most of the time) and if you try to use JS's onUnhandledException (or whatever it is) most errors are essentially just swallowed by Foundry and not detected elsewhere. https://developer.mozilla.org/en-US/docs/Web/API/Window/unhandledrejection_event

atomic briar
#

yeah, the JS events only trigger if an exception reaches the top of the callstack. Because Foundry will often try/catch them and then ignore them, those exceptions never reach the top of the callstack and therefore never trigger an event.

The only choice right now to see them before they get ignored is to patch those Foundry methods that swallow these errors ourselves. This is what libWrapper does, but it's incredibly hacky and a lot of maintenance work.

warm helm
#

The try/catch means that I can't find these errors, hence this request.

brittle gate
#

Well, they're almost always logged, so I'd be surprised if they didn't appear in the console at all. That would be something that needs looking at regardless. Crucially, foundry can't allow these errors to bubble up to the top level unhandled because that will terminate execution, and they're not unhandled because foundry is handling them by catching the error and logging it.

atomic briar
#

oh yeah, they show up in the console. But that's not what I mean by "we want to log them"

warm helm
#

I was wrong in my previous statement. They are in the console, but they don't get detected by unhandledrejection (since Foundry handles them!) and I've no idea how to find the "handled" rejections.

atomic briar
#

LibWrapper's API throws exceptions on multiple situations, but a module might want to handle them. As such, we only warn the user explicitly that there was a conflict if an exception bubbles up to top level unhandled.

LibWrapper will add extra debug information to unhandled exceptions (mainly, which packages show up in the callstack).

Bug Reporter wants to know an exception occurred, to add them to the bug report.

Event Viewer wants to provide the user with a list of all unhandled exceptions, modules in the callstack, etc. Wants to provide the GM with a list of unhandled exceptions on the client side (not all players know to look at the browser console when an error occurs). Etc.

#

just 4 examples of things that can be done with unhandled exceptions... There's probably more. And since Foundry logs them to console and then swallows them, it means we never see these exceptions in the first place.

brittle gate
#

OK, so I think we don't want to be calling them unhandled exceptions, because they are handled. They're just exceptions, and it would be useful to have an easy way to ask to be notified when they occur.

warm helm
#

Exactly. They are handled by Foundry which makes it to where we can't even see they occurred without telling Foundry to basically unhandle them.

brittle gate
#

I wonder if we need anything more complex than just a hook call at all the sites where it currently logs to console.

warm helm
#

I'm definitely out of my expertise here, but it doesn't seem like it'd be more complicated. We just need to know they occurred since Foundry is notified but basically swallows that notification.

atomic briar
#

I don't consider just ignoring an exception to be "handling" it

#

handling implies correcting the issue

#

if you have js catch(e) { console.log(e); ui.notifications.error(e.message); } that's not handling, that's ignoring/swallowing

atomic briar
#

since one of the places you swallow exceptions is inside Hooks._call

#

you don't want an exception inside the hook for an "unhandled" exception, to mean you get into a recursion loop trying to report the new "unhandled" exception

#

but in general, yes it is essentially a Hook call before you ignore the exception. Ideally, before logging it as well (since e.g. LibWrapper may add extra debug information to it).
https://gitlab.com/foundrynet/foundryvtt/-/issues/5020#note_660803394 has an example of how this could be implemented, though the way I handle preventing recursion is a bit hacky and just there as a quick example - a proper implementation would probably instead modify Hooks._call to prevent this recursion

brittle gate
atomic briar
#

I don't think the distinction makes sense. Logging is not handling.

#

remember, JS will log exceptions to console and trigger a "unhandledrejection" or "error" event if they bubble up. Very specifically named "unhandledrejection" and still logged.

#

simply logging is not "handling exceptions". By that definition, a segfault/crash is also "handling exceptions" since it logs the error. Handling implies correcting.

#

but anyway, that's semantics, call the hook whatever you want

#

the reason I used "Unhandled" was because it was meant specifically for errors that aren't corrected. Nobody cares if someone saw e.g. a "File missing" error, and then fixes it by creating the file. What we care about is when they aren't corrected explicitly, since those are the ones that imply a module might be crashing / malfunctioning.

#

in the case of libWrapper, when there's a conflict detected that libWrapper can't proceed, it will throw an exception. A module can (and at least one does) catch that, see it's a known issue, and disable functionality / apply a compatibility patch, in which case I don't care about it. But if the exception bubbles up, I want to warn the user explicitly (with a notification) a module is malfunctioning, since I know exactly which module caused the issue.

brittle gate
atomic briar
#

my point being, it's still unhandled even though it was logged

#

handling implies correcting, logging doesn't correct anything. As you yourself said, it's a last ditch measure - ignoring it (after logging). The issue still occurred, wasn't corrected, and will likely reoccur.

brittle gate
#

Handling an exception just implies doing something with it rather than nothing. Sometimes that's correcting it, sometimes that logging it or providing a helpful message to the user.

atomic briar
#

also, not logging wouldn't crash the entire runtime, the JS runtime is parallel to the exception flow. They don't really share a stack. Nothing prevents them from e.g. just stopping the application or just proceeding with the next runtime tick.

#

it's not like the browser is running the JS engine using a different JS engine

atomic briar
#

but again, call the hook "ExceptionsThatWeHandledByLogging" if you want, I don't really care. It's just that I disagree that doing the same thing the JS engine does when an exception bubbles up is "handling". But that's something more on-topic for #arguing-about-programming than anywhere else at this point.

warm helm
#

Semantics aside, having a hook that just basically "forwards" the error sounds like a great solution.

brittle gate
#

The reason the exceptions are caught is to prevent them from halting execution and leaving foundry itself in a bad state. It already does something that the JS engine wouldn't by allowing the method to continue executing. That is a form of handling. Additionally, the message is logged so that it isn't swallowed silently and that no-one is aware that an error even occurred.

#

Sometimes even with helpful error notifications.

#

So we can forward these errors on via a hook at the sites where they are caught which should provide a reasonable way for modules that are interested in errors to get them. I would also agree that care needs to be taken around recursive errors, possibly by having some special-casing at Hooks._call.

#

If I haven't missed anything, I can go ahead and start working on that for v9. If something comes up that needs clarification I can perhaps ping you on discord or leave a comment on the issue.

warm helm
#

Sounds amazing to me! Thanks for reaching out!

atomic briar
#

yeah, sounds good, thanks!

#

I don't need it right now, but I'd also suggest having the hook get told where the exception got caught (the "cause" parameter in my example, but that name might not be great). I can imagine this could come in useful, avoiding having to parse the stack trace by hand.