Creating error-proof reusable workflows in UiPath

Very well explained but what if I have multiple workflows (more than 100) and as you suggested I have to check the Success flag for each workflow, doesn’t it will impact the performance after using if active for each workflow? Also, is all three variables will be common for all workflows?

Consider the same scenario for library’s and share your thoughts.

Hi @Vinodkumar_Kalkumbe,

You are asking really good questions there. Let me explain.

We have used the above mentioned method in all our workflows both

  1. When workflows are within a UiPath library (which we then consume in the REFramework based dispatcher or performer processes) and
  2. When workflows are within the scope of the REFrameworkf project (dispatcher or performer) itself. i.e., packed within the project.

In both cases the approach we use works great without any noticeable lag or performance penalties in unattended executions. I cannot give you a quantitative answer on this as we have not timed executions to compare the default invoke worklow vs. our approach.

You are right that for example, if you have invoked 100 workflows in Process.xaml file, then there will be 100 checks (if → Success) for the success flag ( one for each invoke ), but the cool thing is that you do not need to save the three variables for each invoke (3 * 300) you need to only declare three variables in the Process.xaml (Success, FailedWorkflowName and ErrorMessage). Each workflow will populate these as they are all going sequential. Note if you are using a for each parallel activity and invoking workflows within them then you probably will need to test this approach works. I doubt it will within a parallel for each.

So back to the example, when the first workflow returns completes successfully, it returns the success flag and null error message and the workflow name. All of these values awill be populated in the corresponding variables.
If after 99 workflows, there is a failure on the 100th invoke, the same Success, ErrorMessage and FailedWorkflowName will be overwritten with new values (False, “Some error message” and “The 100th Workflow”). So the last check (If —> Success=False) will throw an exception as expected.

The maximum number of workflows we have tried in a library is close to 65 and the process has been in production for 7 months without any execution performance issues. The maximum number of workflows packed in a project has been close to 40 and is under testing, with very promising results.

So I can recommend the approach above for Libraries without doubt, but for packed workflows within a project do read the recent posts by @T0Bi in this thread, it has given us some ideas to improve the logging of file names, which we are currently assessing / testing.


a true Robot Master, thank you for sharing.

Hi @jeevith,

Thank you for providing this informative thread to us, I am currently reading the REFramework Documentation and badly needed your opinion. There is a workflow called RunAllTest.xaml file on REFramework wherein it will test all your workflows listed in Tests.xlsx after creating workflows simulating different inputs for success, incorrect data (for business exception), and system exception.

If the ExpectedResult from the Test sheet does not match the result from the Result sheet, the exception will be logged to the comments column and text file.

(image from documentation.)

My TestLog sample

This is all part of REFramework, have you ever tried this?


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.

    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.

1 Like

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.


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:
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:



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.

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.


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

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”.



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.


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


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 Docs

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,

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