Mule 4 error handling deep dive

on error continue main flow

In my previous blog post, I discussed the basics of error handling with Mule 4, helped understand what a Mule error is, what the two major error handling scopes in Mule 4 are, as well as how they work. In this post, I will discuss how to take these basic concepts and build them up so that you can implement error handling strategies in your application (and not be completely lost when doing so).

There are two basic domains to think about when implementing error handling strategies:

  1. Application level error handling
  2. Flow level error handling

In this post, we will dig into how to implement error handling at these two levels and look at examples to show what really happens when you implement different error handling scopes at different levels of your application.

Application level error handling

Often times, in applications you want to implement a sort of fail-safe in case an error is thrown in your flow and it wasn’t able to be caught anywhere within the application. This is referred to as application level error handling and can be implemented two ways:

  1. Mule Default Error Handler
  2. Global Error Handler

Essnetially, these two error handlers reside outside of the actual Mule flows and are used as a last resort when all else fails.

The Mule Default Error Handler is included with every single Mule application and is, at its heart, simply an On Error Propagate without any processors in it. Therefore, if an error occurs and is caught by the Mule Default Error Handler the error is simply propagated up to the requestor (remember: RED in, RED out). One final point about the Mule Default Error Handler is that you cannot configure it — you’re stuck with simply propagating the error with no processing.

So what if you want to configure your “last resort” error handler? That’s where the Global Error Handler comes into play. The Global Error Handler can, unlike the Mule Default Error Handler, be configured to process errors and do what you want with them, therefore you can put an On-Error Propagate or an On Error Continue scope (or both, if you want to handle specific errors) in the global error handler.

Let’s see how these two work! We’ll continue using the same example as earlier in the simple examples section, except this time we won’t define any kind of error handler:

Error handling example

Mule Default Error Handler

What is expected to happen here is that an error thrown by the “Is number” validator will be caught and propagated by the Mule Default Error Handler:

Mule Default Error Handler

* Note that the Mule Default Error Handler is not configurable and therefore is not visually depicted in the flow.

Here’s specifically what is happening here:

  1. Payload is successfully set to “Success – Started Flow”
  2. The Is Number validator creates an Error Object because the payload isn’t an integer
    1. Flow execution stops
    2. #[error.description] = “payload is not a valid INTEGER value”
    3. #[error.errorType] = VALIDATION:INVALID_NUMBER
  3. Because no error handler is defined, the Mule default error handler handles the error
  4. “payload is not a valid INTEGER value” is the error message returned to the requestor in the body of the HTTP request
    1. HTTP Status Code: 500

Global Error Handler

Now, let’s see how this process differs if you utilize a global error handler instead of the Mule Default Error Handler:

global error handler vs mule default
  1. Payload is successfully set to “Success – Started Flow”
  2. The Is Number validator creates an Error Object because the payload isn’t an integer
    1. Flow execution stops
    2. #[error.description] = “payload is not a valid INTEGER value”
    3. #[error.errorType] = VALIDATION:INVALID_NUMBER
  3. The Global Error Handler handles the error
    1. The on error propagate scope catches the error inside the global error handler
    2. The payload is set to “Error – Global Error Handler”
  4. “payload is not a valid INTEGER value” is the error message returned to the requestor in the body of the HTTP request
    1. HTTP Status Code: 500

But wait… this looks exactly as the example where we used the Mule Default Error Handler — why?

Remember, at its heart, the Mule Default Error handler is an error handling scope with just an on error propagate (RED in, RED out) in it. Therefore, when you put an On Error Propagate in the global error handler without any processors in it, it will act exactly the same as the Mule Default Error Handler.

So how do we get the global error handler to return a success (HTTP status code: 200) message? Here’s a hint: RED in, GREEN out.

global error handler return success

The answer is: utilize the On Error Continue scope in your global error handler.

  1. Payload is successfully set to “Success – Started Flow”
  2. The Is Number validator creates an Error Object because the payload isn’t an integer
    1. Flow execution stops
    2. #[error.description] = “payload is not a valid INTEGER value”
    3. #[error.errorType] = VALIDATION:INVALID_NUMBER
  3. The Global Error Handler handles the error
    1. The on error continue scope catches the error inside the global error handler
    2. The payload is set to “Error – Global Error Handler”
  4. “Error – Global Error Handler” is returned to the requestor in the body of the HTTP request
    1. HTTP Status Code: 200

Now that we know how to handle errors at the application level, let’s discuss further how to handle errors at the flow level.

Flow level error handling

Handling errors at the application level is all fine and dandy, but often there is specific logic for how individual flows should react when an error happens within the flow (i.e. reprocessing logic, error logging, etc.) Luckily, MuleSoft makes this pretty simple to deal with by allowing you to put specific error handling logic within each of your flows.

We actually already saw flow level error handling in the simple examples section:

flow level error handling

This is pretty straight forward. But what happens when the errors happen in another flow (i.e. a sub or child flow)?

To demonstrate this, we will use a very similar example to that above, except this example will have the Is Number validator in a child flow referenced by a Flow Reference processor from the parent flow:

Is Number validator child flow

This is where things start to get a little more complex, but just remember your basics when it comes to error handling:

On Error Propagate: RED in, RED out

On Error Propagate RED in RED out

On Error Continue: RED in, GREEN out

On Error Continue RED in GREEN out

Sub-Flow: On Error Continue

Here is our first example (shown above) where the error will happen in the child flow and the error will be caught by an On Error Continue scope in the child flow:

On Error Continue scope child flow
  1. Payload is successfully set to “Success – Started Main Flow”
  2. The Flow Reference calls the child flow
  3. The Is Number validator creates an Error Object because the payload isn’t an integer
    1. Child Flow execution stops
    2. #[error.description] = “payload is not a valid INTEGER value”
    3. #[error.errorType] = VALIDATION:INVALID_NUMBER
  4. The On Error Continue handles the error
    1. The payload is set to “Error – Sub Flow”
  5. “Error – Sub Flow” is returned to the main flow as if the child flow was a success
    1. The Set Payload is executed
    2. The payload is reset to “Success – Finished Main Flow”
  6. “Success – Main Flow” is returned to the requestor in the body of the HTTP request
    1. HTTP Status Code: 200

As you can see, in the above example, because the error was caught by an On Error Continue scope in the child flow (RED in, GREEN out) when the Mule Message returns to the parent flow, the parent flow knows none-the-different that there was a failure because the on error continue returns a 200 success message. Note that because, to the mainFlow, the childFlow appeared to succeed, the processing of mainFlow resumed after the flow reference.

Now, what happens if the child flow returns an error message?

Sub-Flow: On Error Propagate

In the below example, we use an On Error Propagate (RED in, RED out) to handle the error in the child flow. You will notice that this process will look a bit different:

Sub Flow On Error Propagate

* Note that the Mule Default Error Handler is not configurable and therefore is not visually depicted in the flow.

  1. Payload is successfully set to “Success – Started Main Flow”
  2. The Flow Reference calls the child flow
  3. The Is Number validator creates an Error Object because the payload isn’t an integer
    1. Child Flow execution stops
    2. #[error.description] = “payload is not a valid INTEGER value”
    3. #[error.errorType] = VALIDATION:INVALID_NUMBER
  4. The On Error Propagate handles the error
    1. The payload is set to “Error – Sub Flow”
  5. “Error – Sub Flow” is returned to the main flow in the payload as if the child flow was a failure
    1. The Flow Reference fails due to the failure from the childFlow
    2. Main flow execution stops
    3. Because there is no flow error handler for the main flow, the default behavior of a flow is to propagate the error
  6. “payload is not a valid INTEGER value” is returned to the requestor in the body of the HTTP request
    1. HTTP Status Code: 500

Some key difference to note here is that because the child flow utilized the On Error Propagate scope, an error message is propagated to the calling flow (mainFlow). Because of this, the execution of the flow reference in the mainFlow failed and therefore the processing of the rest of the flow stopped. It is because of this that the final set payload processor didn’t execute and the error message was passed back to the requestor.

A final note on this example is that there is no error handling defined in the mainFlow and therefore, the error is simply propagated again as the default behavior of a flow is to propagate the error.

Now, knowing what we know, how could we get this same example to return a successful HTTP status code of 200?

  1. Put an on error continue in the child flow (previous example)
  2. Add an additional on error continue to the main flow to handle the error
    1. Note: In this case, the final set payload processor wouldn’t execute
additional on error continue main flow

Now that we know how to handle errors at the flow level, in my next (and final) installment of this three-part blog, we’ll take a look at how we can more granularly handle errors within a flow through the use of processor level error handling and specifying specific error handling strategies for specific errors. To learn more about the latest version of our runtime engine, check out What’s new with Mule 4?



We'd love to hear your opinion on this post


6 Responses to “Mule 4 error handling deep dive”

  1. very informative and nice blog for mule 4 error handling

  2. Kyle

    Awesome post and loved the way you’ve explained it in detail, it cleared my confusion as well.

  3. Hi Kyle,

    The blog cleared most of my doubts wrt Error handling in mule.

    Thank you very much for the blog.

    I have a question here,

    In the Sub-Flow: On Error Propagate section, why is that the body has the message – payload is not a valid INTEGER value

    instead of it being – Error – Sub Flow

    Can you please help me with this.

    Thanks
    Kalyan

  4. Thanks for spending time for such a great tutorial. Really explains the actual concept of mule 4 error handling with simple and easy to understand example. Thanks again for spending your quality time to prepare and and publish this tutorial.

  5. Hi Kalyan,

    Remember that an on error propagate is red in, red out meaning that no matter what happens in the processors of that given error scope, an error object is what is returned. In this case, the error object that was created had the error description of “payload is not a valid INTEGER value” as the body and that is why that was the message returned to the requestor.

    Hope this clarifies things.

    Thanks,
    Kyle

  6. Let us say in the “Sub-Flow: On Error Continue”, i put a logger that prints the payload before “Set Payload Success – Finished Main Flow”. What will this logger will print? Basically i want to what happens to the original payload once an error occurs?