Exception Handling – The basics

Like the name says, an Exception should be an Exception, i.e. we should write our code properly to avoid unexpected scenarios by validating action inputs, checking if database is returning information, services are answering correctly and so on…
When it’s not possible to think in all possible scenarios, exceptional application errors might occur during the application runtime. We call them Exceptions, because they should be exceptional errors.

In this article, I’ll cover some aspects in Outsystems exception handling, where all of them should be well known for every single developer BUT I’ve seen some being completely ignored and misused.

1. Exceptions lose their type between modules.

This is one of the most annoying aspects of OutSystems development.
Exceptions defined in one module (such as ValidationException, RecordNotFoundException, or ConcurrencyException) will result into a GenericException when caught in another module.
This prevents them from being handled in a meaningful, type-safe way.

When you manage dependencies for a single module, you cannot reference User Exceptions from another module.

In some of previous articles I’ve already shown that we should validate inputs in every single action on every single module. Let’s consider what we’ve learn on Create or Update CS Pattern. We ended the article by throwing different type of exceptions, depending on what problem we detect:

  • If no name or a duplicate email address is provided, we throw ValidationException;
  • When we try to update an unexisting record, we thrown a RecordNotFoundException;
  • Each time a concurrent update is detected, we throw a CuncurrencyException;

While this makes perfect sense, when this exceptions are handled by an Exception Handler in another module, they are catch as GenericExceptions.

This is annoying because you cannot handle exceptions accordingly.

One of other patters that I use is, in Business Layer actions to validate if the user has the required role to perform the action. If the user doesn’t have the required role then I throw an UnauthorizedException. It would be nice to be able to reference UnauthorizedException from the Frontend module and handle it accordingly in OnException action.

2. When you drag an Exception Handler to a Server Action, Service Studio automatically sets “Abort Transaction = Yes”

Why I’m considering this a dangerous behavior?

When Abort Transaction = Yes is set in an Exception Handler, the transaction is aborted automatically. This can lead to unexpected rollbacks if your logic relies on a simple Boolean success flag.

Sometimes I see an awkward pattern in code from existing projects, and the pattern is the following:

  • In business actions, there’s a return parameter that signals if the operation run with success;
  • There’s a handler for AllExceptions, with Abort Transaction = YES;

Let’s discuss this…

You cannot assume that one action is only called directly from a React Frontend action. Actions can be called from other orchestrator actions, so if some Exception is thrown by whatever reason, your action aborts the transaction, starts a new one and returns a Boolean signaling a problem … you might have created a timebomb for possible data loss and inconsistency.

An issue created with this pattern is that from now on you MUST check IsSuccess value after invoking the action. I’ve already seen this pattern applied and IsSuccess not being checked.

Consider setting Abort Transaction = No and rethrowing exceptions to be handled at a higher layer, where you have better control

3. Exceptions should only be caught if they can be resolved.

This is a golden rule. If you cannot solve the problem, you should let it be handled by some who can.
If your code looks like the example on 2, you are simply hiding the problem. Your business action can be called from other module that has the ability to understand the problem and solve it. By returning the success boolean you are missing the opportunity for the caller to deal with the exception accordingly.

4. You, as a developer, must handle exceptions accordingly

In the end, it’s your responsibility over the code you write. If you don’t handle exceptions accordingly you might end with data loss or inconsistency in your application.
Sometimes is quite difficult to find the origin of the problem because it happens randomly and typically when you detect that your data is inconsistent, it’s already too late.