Creating error-proof reusable workflows in UiPath

Hi @Kenneth_Balana,

We had tried this (unit-testing) within the REFramework in the initial stages of our CoE establishment. To keep the development and test phases separate, we choose to use Test-Suite instead where we can test all the activities we developed for a given project and perform integrated test (similar to the flow of process we are automating).

  • We modify the UiPath test-suite to our use case and write outputs to a custom excel file depending on the process we are automating.

  • The “test cases” in the test-suite can also further be tested using a “test robot” license on a prod-like VDI or alternatively in AzureDevops (Tests) before deployment.

  • Our final test phase is to run the robot for the suggested Cochran’s Sample Size given the expected cases for the robot (population). This sample size gives us number of test cases to be run before we can represent the outcome to the entire population of robot cases. We require a minimum of 90% test cases are success. We try to keep the p sample proportion to 0.5 as we have no observed evidence towards success or failure in the testing population.
    image

    We run this test in REFramework process on NonProduction license so that we have a robust robot which tackles production-like environment and data. If we do not meet the success ratio, then we have to identify where the most failures originated, fix it and run the test for the same sample size.

But if you have regime for unit-testing, the inbuilt Tests folder in the REFramework is a useful tool.

2 Likes

Thanks, @jeevith

I’m on the initial stage of my RPA journey and this information was too much for me to understand in just one sitting, but I am glad that you are sharing this with everyone. I want to learn more from this do you have a site or blog post for this? I want to learn more about the final test phase you have like what about the confidence level with precision etc.

Hi @Kenneth_Balana,

I will try to make a tutorial on RPA testing (how to validate test runs) in the coming weeks. Currently, I am working on another tutorial on automating the documentation of workflows using PowerShell.

RPA is a great career to start with as you will quickly learn a lot about not just building robots, validating their performance and communicating their value to the stakeholders. You can take the learnings from this field to many other fields, be it data science, machine learning or business development. But my advice to you as you are starting out is to just repeat the basics. 80% of a RPA developers workflow is based on the basics course.

Like Bruce Lee quotes: I do not fear a person who has practiced 10000 kicks, but I do fear the one who has practiced 1 kick 10000 times.

I wish you great success in your RPA endeavours.

3 Likes

An interesting post and discussion. When you say “process level” do you mean, bubble up the exception and let the calling code decide what to do?

Hi @tsverthoff,

That is correct. Such that the process logic decide how to handle the bubbled exception.

This makes code maintenance easier as the workflows being called (invoked) just do what they were supposed to do and if an exception occurs report that to the process level using the Success flag and ErrorMessge arguments.

@jeevith - Sorry to keep extending this, but this is an important thread for people who are new to UIPath and how to use Try/Catch with UIPath.

Using your workflow model: If an exception occurs in the called workflow which is not explicitly listed in the Catch activity, does the automation crash in the called workflow?

This raises a further question of how to develop an appropriate list of specific exceptions to catch? Of course you can Google “exceptions for file I/O” but is that the best way to find an appropriate list of exceptions for whatever is in the try block?

Hi @tsverthoff,

That is a good question. The reason we use a very generic type of exception (system.exception) in the invoked workflow is to ensure that all kinds of application exceptions are caught. At any given point a workflow will never have 2 exceptions so using a generic catch exception in this case is the way to go.

If you know and expect a particular exception, you can have additional catches in the proposed workflow and if an unknown type of exception occurs, the generic type ( system.exception) will catch that exception for you. I have a thread which explains further how specific and generic exception are caught in UiPath : Exception Handling Query - Help / Studio - UiPath Community Forum

With the proposed approach one can be sure of catching all kinds of exceptions. We have used this method on over 1 million transactions so far and have always been able to pinpoint where in the process an automation failed and the corresponding failure message.

Hope this helps.

Note: I am saying this in a speculative manner as I try to figure out how UIPath does things.

I’ve been looking into this a bit more and 2 things have occurred to me:

  1. UIPath apparently does not do “exception swallowing”. No matter what exception gets thrown the value of exception.message is always correctly set to the granualar exception message, rather than to a generic exception message. In UIPath it doesn’t seem neccessary to catch anything other than system.exception.

  2. Some Activites return a boolResult and some don’t.

02.01. If the Try Activity returns a boolResult:
02.01.01. Initialize out_Result to False.
02.01.02. Create an If/Then/Else based on the Try Activity boolResult and set out_Result as appropriate.
02.01.03. In the Catch System.Exception, set out_Result to False again. I have the vague impression there was a traversal path where this was necessary, but it doesn’t hurt.

02.02. If the Try Activity does not return a boolResult, UIPath seems pretty good at raising any problem as an exception. For example, ReadCSV does not return a boolResult, but anything that goes wrong with the file path is automagically raised as an exception which you can catch with System.Exception. You don’t need to do any explicit (non-exception) error handling.
02.02.01. Initialize out_Success to True.
02.02.02. If anything goes wrong an exception will be raised, caught by System.Exception, and out_Success is set to False. If no exceptions occur, we assume that everything worked correctly and out_Success remains True.

Hi @jeevith

This is a great post :+1: and think you did a great job explaining it. I think the reason why this works is because its ‘simple’ and thats very important for scale!

And as you said - it scales!:

I am not an expert by any means but can I just try and add an idea to your great post. My idea is about the out_ErrorMessage argument.

Have you ever updated the out_ErrorMessage to include the following:

  • “Exception.Source.ToString” - to know which activity was throwing error.
  • “Exception.Message.ToString” - to get the exception message.
  • “Exception.InnerException.Message.ToString” - to get a more detailed exception message.

I would update it to something like this:
Step 1: Simply just update out_ErrorMessage as normal.
Step 2: Then insert an Assign activity with the following:

Assign Left:
out_ErrorMessage
Assign Right:
out_ErrorMessage + ". Exception Source: " + Exception.Source.ToString + ". Exception Message: " + Exception.Message.ToString + ". Exception Inner Message: " + Exception.InnerException.Message.ToString + “.”

This will append all the above extra details onto the argument out_ErrorMessage without updating your code beyond inserting 1 Assign activity. I think this would help a little bit more for targeted troubleshooting. I thought, if you go to that amount of effort you should catch as much information as possible and not be so heavily reliant on the developer’s custom description. Also the above message would be very Copy+Paste friendly.

You may have tried/considered this but thought I would share it anyway.

Keen to hear your thoughts :blush:

Cheers

Steve

1 Like

Hi @Steven_McKeering,

Thank you for your wonderful inputs. We do use the Exception.Message in the catch block, but Exception.Source and Exception.InnerException.Message are insightful information to include in the out_ErrorMessage.

I completely agree with you that it is worthwhile forwarding all possible information about Source and InnerException to the parent/process workflow as well. As you noted the base is already set and we only have to add these two information strings in out_ErrorMessage argument.

Action:
I have updated the Zip file in the original post and the template workflow is updated with the following

Catch Block —>Assign:out_ErrorMessage and Log message
out_ErrorMessage= exception.Message+"|Exception Source:"+exception.Source.ToString+"|Exception Inner Message:"+Exception.InnerException.Message.ToString+"|"

The final log message would have a fixed pattern to make it easier for further transformations.
The | character is used to ensure that this separator can be used by any visualization software. Regex can be used to fetch the different values of keys. I also do not like spaces or newlines in log messages this way the extracted values from regex do not need to be trimmed in some of the visualization software.

|Key1:Value1|Key2:Value2|...|Key3:Value3|

Testing:
Case 6 : Invoking workflow which has an unexpected error
I ran the Case 6 test again to confirm the changes are updated:
image

Once again, I appreciate your feedback through which I learnt something new today :+1:

1 Like

Hey @jeevith

Just a small note from my previous reply.

InnerException message is sometimes blank which needs to be handled correctly. So use an assign inside a try catch. With the catch’s purpose to give it a default value of something like “No innerexception message found”.

Cheers

Steve

1 Like

Hi @Steven_McKeering,

I appreciate your very thoughtful inputs :slight_smile:

A check on a string is empty or null can be another alternative to Try and Catch. I try limiting the use of try catch on activity level and rather use it on a workflow level / wrapper level (invoked workflow/s within a wrapper) and let the Process.xaml decide how the error needs to be thrown to Process Transaction state.
I have found that this approach ensures easy debugging provided all the three arguments (out_Success, out_ErrorMessage, and out_FileName) can be accessible by the Process.xaml.

Yes one disadvantage will be that an additional log message (error type) is written by the Throw activity in Process.xaml. This is in addition to the error message being written by the catch block of the invoked workflow.

2 Likes

Hi @jeevith

Thank you for Presenting this workflow. Just want to understand how the Error message will display the activity name using Exception.source…coz exception.Source name can either fetched using rethrow activity or by not including the try catch block in the invoked workflow. In error message source will always display as “Throw” correct like in your message box. It is better we can use Rethrow activity which gives both exception message and source. Just my thought

Thanks,
Boopathi

Hi @Boopathi.M,

  • I personally avoid rethrowing exceptions in the catch block of the invoked workflow as it will also bubble the exception to Process.xaml.
  • If we remove the try catch, we would not be able to catch unexpected failures.

In the newest version, observe that a part of the error message (in the catch block) will fetch the Exception.Source (where did the try block fail). In this example, it was Exception Source:mscorlib

This out_ErrorMessage argument can then be accessed by the parent workflow, for example, Process.xaml.

Essentially, the child workflow communicates where the issue was to the parent workflow. It is upto the parent workflow to handle it as required. In case of REFramework, the developer can choose to either handle this exception by throwing after a check like the image below and let the Process Transaction State take care of marking the QueueItem with the correct Transaction Status:

Here is additional documentation on how Exception.Source (The name of the application or the object that causes the error.) can be obtained : Exception.Source Property (System) | Microsoft Learn

I hope it helps clear your doubts.

Hi @jeevith

Thank you for your explanation. Yes, exception source actually displays activity name or object(in out_errormessage) based on how we use in our workflow and there is separate discussion there in forum in displaying activity name using exception.source. Just wanted to give it as feedback as we will still need to identify the actual activity which caused error using logs or by debug method but it will help us to identify on which xaml actually error has occured just by looking at logs and it really helps a lot in exception handling. Thank you for your effort in presenting this idea in forum.

Thank you,
Boopathi

Hi @Boopathi.M,

I am glad it has helped you. Thank you for your inputs and discussion once again.

The above approach we suggest will also work on UiPath test cases, libraries or processes.

1 Like

Hi, I am new to this and wanted to know:

  1. Is this still relevant and a good practice to track errors?

  2. When using the tutorial files I am lost what to do and how to use it and I would really appreciate if someone could explain:

a) In the main file the RobustWorkflowTemplate is invoked. Then in the invoked template I am asked to edit the out_FileName (this I do not understand)?

b) In next step/sequence “Any Specific Logic” I am supposed to insert my RPA (MyExampleRPA)?

c) The tutorial is called “TutorialRobustWorkflow” starting the RPA with the main file, so if I want to use it I need to rename the “TutorialRobustWorkflow” into my RPA name (MyExampleRPA) and then insert the activities (from the original MyExampleRPA) into the “Any Specific Logic”?

As you can see I am lost - please help.

One approach that’s been a game-changer for me is leveraging well-defined exception handling.

Could you write a little more about your approach?

Think of it as a safety net for unexpected hiccups. Think of it as a safety net for unexpected hiccups. By incorporating try-catch blocks, we can gracefully handle errors and prevent our workflows from derailing.

Another secret weapon is building modular components. Imagine your workflow as a Lego set - individual, reusable building blocks that can be snapped together for various tasks. This promotes code reusability and simplifies troubleshooting. Plus, it makes scaling your automations a breeze!

For those UiPath wizards out there, what are your favorite techniques for constructing bulletproof workflows? Share your wisdom in the comments below!

P.S. Speaking of building strong teams, if you’re looking for some top-notch remote developers to join your UiPath force, check out Hire Full Stack Python and JavaScript Developers | Huntly.