Transition from catches="complete" workflow step not working

Which IIQ version are you inquiring about?

8.3p3

Share all details about your problem, including any error messages you may have received.

I am trying to catch a workflow error and transition to Approve and Provision step of the workflow in case of a specific error but the workflow doesn’t transition and the workflow ends after the Catch Step.
When there is already a request pending for the user in a SAP System, executeUserAccessRequest of the SAPGRCIntegrationLibrary throws an error message.
My Usecase is such that if there is already a pending SAP GRC request for the user, I want to retry the SAP GRC request again but I am not able to see the workflow transition from Catch Step incase of an error. Has anyone achieved this or have any ideas?
Below is the updated logic of the LCM workflow

<Step catches="complete" icon="Catches" name="Catch Step" resultVariable="isretrySAPRequest">
    <Script>
      <Source>
        import java.util.ArrayList;
        import java.util.Iterator;
        import sailpoint.tools.Message;
        import sailpoint.object.IdentityRequest;
        import sailpoint.object.WorkflowCase;
        import org.apache.log4j.Logger;
        import org.apache.log4j.Level;

        Logger logger = Logger.getLogger("com.workflow.LCMWorkflow");
        boolean isretrySAPRequest = false;

        logger.error("Inside Catches step");

        WorkflowCase wfc = wfcontext.getWorkflowCase();
        List messages = wfc.getMessages();

        if (messages != null &amp;&amp; !messages.isEmpty()) {
        for (Object obj : messages) {
        Message msg = (Message) obj;
        if (Message.Type.Error.equals(msg.getType()) &amp;&amp; msg.getMessage().contains("There is already an open request for system")) {
        isretrySAPRequest = true;
        wfcontext.setVariable("isretrySAPRequest",isretrySAPRequest);
        break;
        }
        }
        }
        return isretrySAPRequest;
      </Source>
    </Script>
    <Transition to="Approve and Provision">
      <Script>
        <Source>   

          if("true".equalsIgnoreCase(isretrySAPRequest)){
           log.error("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ go to Approve and Provision");
          return true;
          }
          return false;

        </Source>
      </Script>
    </Transition>
    <Transition to="Finalize"/>
  </Step>
  <Step name="Finalize">
    <Arg name="autoVerifyIdentityRequest"/>
    <Arg name="project" value="ref:project"/>
    <Arg name="ticketDataGenerationRule"/>
    <Arg name="priority" value="ref:workItemPriority"/>
    <Arg name="trace" value="ref:trace"/>
    <Arg name="identityRequestId" value="ref:identityRequestId"/>
    <Arg name="approvalSet" value="ref:approvalSet"/>
    <Arg name="ticketManagementApplication" value="ref:ticketManagementApplication"/>
    <Arg name="batchRequestItemId" value="ref:batchRequestItemId"/>
    <Description>
      Call the standard subprocess that can audit/finalize the request.
    </Description>
    <WorkflowRef>
      <Reference class="sailpoint.object.Workflow" name="Identity Request Finalize"/>
    </WorkflowRef>
    <Transition to="ModifyTask"/>
  </Step>

Believe what you’re seeing here is expected behavior. I’d recommend changing things around here to fit your use case.

The catches=”complete” step runs when the workflow completes normally or has been terminated because of a failure, so by the time this step runs, the workflow execution path is done. It’s not the place to handle retry logic.

Would recommend instead moving the logic to a normal step and wrap in a try/catch block. When you get the error for a pending request, you can set a retry counter and transition to a Wait step, then loop back to your execution step to handle trying the request again.

Hi Srikanth,

Can you please try below fixes:

  1. In your xml, inside your script, isretrySAPRequest is a boolean but you’re comparing it with true".equalsIgnoreCase(...) as if it’s a String.
    change it to like below
return Boolean.TRUE.equals(isretrySAPRequest);
  1. Wherever you are calling executeUserAccessRequest, add the try/catch in
try {
    executeUserAccessRequest(...);
    wfcontext.setVariable("isretrySAPRequest", false);
} catch (Exception e) {
    if (e.getMessage() != null &amp;&amp; e.getMessage().contains("already an open request for system")) {
        wfcontext.setVariable("isretrySAPRequest", true);
    } else {
        throw e;
    }
}

Hi @naveenkumar3 , @robert-hails - The method executeUserAccessRequest is from the connector jar and we call it in the workflow as below -

<Step action="executeUserAccessRequest" icon="Task" name="Execute Request" posX="176" posY="11" resultVariable="requestNumber">
    <Description>
      This step will execute User Access Web service based on the maps received from the previous step.
      On successful execution of the web service a request number will be returned.
    </Description>
    <Transition to="Check Request Status"/>
  </Step>

can you try below please and let me know, if it works

<Step icon="Task" name="Execute Request" posX="176" posY="11" 
      resultVariable="requestNumber">
  <Description>
    Executes User Access Web service based on the maps received from the 
    previous step. Sets isretrySAPRequest flag if a pending SAP GRC 
    request already exists for the user.
  </Description>
  <Script>
    <Source>
      try {
        Object result = wfcontext.getWorkflow().call(
                          "executeUserAccessRequest", wfcontext, args);
        wfcontext.setVariable("isretrySAPRequest", false);
        return result;
      } catch (Exception e) {
        String msg = (e.getMessage() != null) ? e.getMessage() : "";
        log.error("Execute Request caught exception: " + msg);
        if (msg.contains("There is already an open request for system")) {
          log.error("Pending SAP GRC request detected - flagging for retry");
          wfcontext.setVariable("isretrySAPRequest", true);
          return null;  
        } else {
          throw e;
        }
      }
    </Source>
  </Script>

  <Transition to="Approve and Provision">
    <Script>
      <Source>
        Boolean retry = (Boolean) wfcontext.getVariable("isretrySAPRequest");
        return Boolean.TRUE.equals(retry);
      </Source>
    </Script>
  </Transition>
  <Transition to="Check Request Status"/>

</Step>

Steps with catch = "complete" act as finally steps in the workflow and are always executed. There should be no transitions to this step. Any transitions from other steps, as well as from this finally step itself, should go directly to the End step.

@srikanth_akella8 Have you tried enabling provisioningRetries to see if it goes for retry or not without modifying LCM? You need to define specific error’s substring to have retries on it.

Hi @naveenkumar3 - The solution you have shared worked perfectly with slight modification after Importing the SAPGRCIntegrationLibrary class.

I have made slight modifications in the try block as below -

try {

    SAPGRCIntegrationLibrary sapGRCIL = new SAPGRCIntegrationLibrary();
    Object result = sapGRCIL.executeUserAccessRequest(wfcontext);

}
catch(Exception e){

}

and as suggested in your solution, we are able to catch the error and check the message.

Just out of curiosity, how do we pass args in
Object result = wfcontext.getWorkflow().call(
“executeUserAccessRequest”, wfcontext, args);

Thanks,
Srikanth

Hi Srikanth, Glad it worked. Please mark the post as solution, as it will help other with same issue. You can try like below

The third parameter args is a Map , so you can pass it like:

Map args = new HashMap();
args.put("paramName1", value1);
args.put("paramName2", value2);

Object result = wfcontext.getWorkflow().call("executeUserAccessRequest", wfcontext, args);

Thanks all for sharing your ideas and knowledge.