HCM Processes & Forms: Forwarding Errors….what to do when the stuff hits the fan!
You built the perfect process. It is a thing of beauty. Efficient. Well-designed. It could not be better. All is good……until it is not!!! What happens when your workflow is set to save data and something goes wrong? Maybe an employee is locked? Maybe there is authorization missing? Maybe there is a “collision” of processes (ex. trying to give leave to someone is in the middle of being terminated)? You absolutely do not want your beautiful process to go “off the rails” and into “never never land”. Thankfully, SAP has a nice way to handle these “unforeseen” errors and set your process back on track! Years ago, I had to trace this through for myself and recently, it came up again as a client’s employee stumbled upon it. I had to explain it to him and thought “hey…that would make a good blog!”….so here we are. (haha)
When saving data in background (using something like the standard task (TS33700034) and/or workflow template (WS33700044 – Save Form with Error Handling WD), you might be wondering “what happens when an error occurs?….I mean it cannot save the data so it goes somewhere, right?”. The answer Is in good ol’ consultant speak “it depends”. It all hinges on “how” you configure your processes to handle errors and what kinds to handle. Our possible options for “error categories” that we can “catch” are:
These cover about everything we might encounter. So how do we set it all up?
First, how do we define what errors we respond to and where they should be passed along to? This is in the IMG along the path….
Here is an example of the configuration…
As you see, we select an “error category”, set it’s “priority” (more on that later) and then “who” it should route to in the event of that error.
From the configuration documentation, it tells us:
“You use the error category to define which expert is forwarded a workflow step for error processing. If errors from different error categories occurred when processing user input, then the error category with the highest priority determines which expert is forwarded the current workflow step to handle the errors.”
And in the IMG node documentation:
“Assign values between 1 and 99 where 1 represents the highest priority. The error category with the highest priority determines which expert is forwarded the current workflow step to handle the errors first. If several error categories are prioritized equally, only one error category with this priority is included. Which of the error categories this will be, depends on the database system. If you want to provide the same agent(s) for several error categories, you do not need to enter the data for each error category individually; instead, you enter the information for the OTHERS error category.”
Keep this in mind for how this table is read as we will discuss later.
And if we look at the actual table used, it is T5ASRERRORAGENTS (aka “error agents”)…
So now it is all configured, but where and how is this configuration used?
Second, “where” and “how” are the errors caught and handled? The magic begins in standard SAP class CL_HRASR00_WF_COMPONENTS (makes sense because this happens in workflow). You will notice the “save data” workflow task calls this class and method SAVE_FORM_DATA_TO_DB_WD. If you look in method SAVE_FORM_DATA_TO_DB_WD , you see it just passed on to method.
If we look at method MAINTAIN_FORM_DATA_WD, you can see what it does if an error occurs…
As you can see on line 349, this passes us to method SERVICE_FOR_ERROR_HANDLING_WD.
Method SERVICE_FOR_ERROR_HANDLING_WD first loops through all of our messages which are errors, aborts or warnings with a preference to errors/aborts and collects the details in its own “Error Infos” and “Warning Infos” internal tables. Now if this table has any entries, this is where it checks our configuration for “Error Agents” mentioned earlier. It does this by calling a standard function HR_ASR_HIGHEST_PRIO_AGENT.
A nice additional feature is that regardless of what the function says (ie. “who to send to or not”), it still will write any errors to the application log.
So what does that function HR_ASR_HIGHEST_PRIO_AGENT really tell us?
First it pulls/reads in all of our entries in configuration for “Error Agents” (T5ASRERRORAGENTS). If you have missed this configuration or do not have entries in this table for some reason, it will fall through to an exception…
But let us assume, you do have “error agents” defined.
Second, for any listed as “all other categories” (ie. key “OTHERS”), it will replace the “other” with all other categories set to the priority the “others” was set too. This allows us to easily set ONE “agent” to handle all errors. For example, if we have our configuration set as….
Error Cat. Priority Agent Type Agent Object Name
All Other Categories 3 Rule 17900016 Personnel Administrator of Person
When this logic section runs, it will “explode” this out to then be….
Error Cat. Priority Agent Type Agent Object Name
Exception When…Database 3 Rule 17900016 Personnel Administrator of Person
Data Collision 3 Rule 17900016 Personnel Administrator of Person
Exception When…Expert 3 Rule 17900016 Personnel Administrator of Person
Inconsistent Data 3 Rule 17900016 Personnel Administrator of Person
No Authorization 3 Rule 17900016 Personnel Administrator of Person
Object Is Locked 3 Rule 17900016 Personnel Administrator of Person
Exception When… Object 3 Rule 17900016 Personnel Administrator of Person
Error Workflow Runtime 3 Rule 17900016 Personnel Administrator of Person
Incorrect Customizing 3 Rule 17900016 Personnel Administrator of Person
Now the fun begins…
It then sets a variable for “highest priority” as 100. Remember, our configuration has priority settings too…
This is likely very confusing (thanks SAP!). The priority in our configuration is limited to 2 characters….meaning 1 through 99. It sets it’s own “initial” variable of “highest priority” as 100 since 100 is greater than our maximum of 99 in configuration. The confusing part is that “1” would actually be “highest” priority and “100” would be lowest possible. Just keep that in mind….lowest number is highest priority.
Now it will look to see if our actual “error category” is configured for any of the errors that occurred. If so, that entry’s “priority” setting will become the new “highest priority” if it is less than our “highest priority” variable value (see line 54…again, lowest number is highest priority).
Now it will look to see if our actual “error category” is configured for any of the errors that occurred. If so, that entry’s “priority” setting will become the new “highest priority”.
So if highest priority is still 100, we must be missing some configuration or have a problem. In that case, the condition results in…
However, let us say that we did find one and highest priority is 99 or lower. This next little bit of logic is kind of “weird” in my opinion. So now that we found our matching “error category” in our “error agents” and have that “priority” value as “highest priority”, it then goes back again and loops through all the “error agents”.
As you can see, for any of our “error agents” that have the same priority as our “highest priority”, we store those in a new internal table called “highest priority agents”. Basically, we found the matching error agent entry for our very specific error category previously, but now, we are saying “hey just give me all the error agents with that same priority regardless of type of error”. Huh? But there is more…
So now we filtered out our “error agents” configuration table entries to just the ones who’s “priority” matches the “error category” entry from our “error agents” found before. Now, we go back through our actual errors (errors or aborts) and compare our “error category” against the “highest priority agents” table we just created. Now, we set “highest error category” to the “match” it finds in “highest priority agents” with the same “error category”. Confused yet? (haha)
Basically, I think the developer is simply trying to save the customer from themselves…..from being able to have more than one entry in the table with the same error category and/or priorities.
Finally, it merges in the “warnings info” table (built from just “warnings” previously) into the “error infos” table (which could be errors or aborts). Then it loops through this “combined” table and deletes any entries where the “error category” does not match what we determined the “highest error category” to be in all that convoluted logic earlier.
So in the end of this, it will pass back:
- ERROR_MESSAGE (aka “error infos”) – basically the error details like a typical “message” table
- ERROR_CATEGORY : the category of error that should match what are “error agent” table would be looking for
- EXPERT_WITHDRAW_BUTTON_VISIBLE: just as it says…whether the “withdraw process” button should be visible or not
Ok….so we now how it reads our configuration to determine which “error category” is picked based on priority and other factors, but as we can see, it does not pass back anything about “who” to send the error too. How does that happen?!?! Glad you asked…
Third? We know “how” we configure the errors we catch and we now know “where” those get picked up/read/caught, but now, how does it know “who” to route this too?….especially since all we used our T5ASRERRORAGENTS table for before was checking “error category” and “priority”. If you notice when you include the “save with error handling” standard workflow template, you will see this rule on the “Error When Saving Automatically” task…
With the binding to the agent determination set as:
If we go to transaction PFAC to view this rule…
…it has this nice and very informative description…
…and is defined as…
You can see that it calls function module HR_ASR_ERROR_AGENTS. You can also see that the “container” simply passed over the “error category”. Can you guess what happens in the function HR_ASR_ERROR_AGENTS? (Haha)
As you should guess, it simply looks up what the object type and object id defined for the “error agents” (table T5ASRERRORAGENTS) that match the “error category”. If you refer to the IMG documentation when configuring this, you will notice that it is pretty much open to any typical option for an “agent” (role, org unit, job, position, user id, work center and even using another rule!). This is how it knows who the item should go to in the event of an error. Magic!
PUTTING IT ALL TOGETHER (Workflow)
Now to put it all together…..it really comes down to two simple tasks you need to make sure are in your workflow (if not using the standard error handling one).
You see the “Save Form Data WD”? Notice what we get back from it when it attempts to “save”….
So there in the second part of the flow at the “condition check” step, you see we check the container value PROCSTATE for errors.
If an error did occur, it then will pass to the “Error When Saving Automatically” step and pass it the previous “error category” container value in the bindings.
As we previously described, THIS is how we know not only “what” error occurred and “how” to handle it based on our configuration of “error agents”, but also “who” it needs to then route too in order to be handled further.
Now you know more than you likely ever wanted to know about the way SAP keeps the process moving along when it goes slightly “off the rails”. I know for me at least, the set up of this seemed a bit overly complicated and/or not very well documented. I had to take matters in my own hands and just figure it all out to the “nTH” detail for myself one day long ago…..and now I shared it with you! I hope it helps, and as always, I will keep blogging if you keep reading them! Till next time….