BpmnError and Displaying Exception description

Hi

I have some boundary exceptions attached to some service activities where make REST calls and as a result potential exceptions are being delivered from the endpoints which are mostly within 4xx family. Whenever I invoke a BpmnError all Im getting on the postman is the standard Camunda internal 500 error. Is there any way to overwrite this by passing the received value instead of the Camunda’s 500 internal error? Any guidance on this would be appreciated.

Thanks

Hi @cobalt ,

In general if you send a BPMN error you should get a 204, if the call is successful. If you get back a 500 that means that the process instance could not resume the call. So the BPMN error is not handled on engines side.

how are your service task implemented? Are you using connectors? Then this discussion might help you here.

In general you might want to check if you could implement your service task as external task workers, as sending a BPMN error is a little bit more straight forward and can be implemented by using this REST call.

I hope that helps, cheers
Nele

Hi Nele

I have 3 Delegate files and a 3 Service layers which are being called from the respective Delegate files.

My BPMN is a straight line, 3 service calls and checks which takes a draft submission, stores into a microservice using spring webclient and uses the newly created and returned object to be passed onto the final microservice for final creation. I call the delegate using the expression implementation ${nameDelegate.create(execution)} where the logic sits.

Issue is that the flow works without a problem, unless an exception is thrown form the microservice which in term when I use the boundary exception and BpmnErorr, I keep on getting the 500 internal exception without any resolve and no description whatsoever.

I tried this on 2 separate fresh installation thinking some other library might be causing a conflict without resolve.

I am also using Camunda 7.14.0.

In regards to using external calls, it is not feasible as the system has hundreds of microservices which are being discovered on the network and calls typically use @RegisteredOAuth2AuthorizedClient for assigning the authorisation info for each service calls, hence the embedded format.

Could this be a bug or is it something Ive missed here that is causing this problem.

Thanks

Hey @cobalt ,

have you set an asynch before, on the service tasks? Could you share the model?
Just one more question: are you throwing the bpmn error from your delegate code or from an independent REST Call? (you said you use postman for it?)

Kind regards
Nele

Hi Nele

Yes I did, it shows an error has occurred, I have attached the model below.

The way I’m throwing the BpmnError is inside the logic, so will make a webclient call if that throws an exception, I’ll catch it and subsequently trigger the BpmnError. I use postman as I have created an endpoint that initiate the process and thereon delegate and service layer handle the logic.

Delegate Logic:

public void create(DelegateExecution execution) {
    oneService.create(execution);
}

Service Logic:

public void create(DelegateExecution execution) throws Exception {
    this.microserviceDiscovery.setServiceId(ID);
    this.microserviceDiscovery.setEndpoint(ENDPOINT);
    this.webClient.mutate().baseUrl(BASE_URL);

    try {
        FinalClassDTO responseEntity = webClient
            .post()
            .uri(microserviceDiscovery.getUrl())
            .attributes(oauth2AuthorizedClient())
            .accept(MediaType.APPLICATION_JSON)
            .contentType(MediaType.APPLICATION_JSON)
            .body(BodyInserters.fromValue(CamundaVariableHandler.getObjectDTO(execution)))
            .retrieve()
            .bodyToMono(FinalClassDTO.class)
            .block();

        CamundaVariableHandler.setFinalClassDTO(execution, responseEntity);
    } catch (RuntimeException e) {
        throw new BpmnError("errorOne");
    }
}

Thanks

P.S. Postman returns 500 with Internal Service Error as a message when a BpmnError or RuntimeException is thrown.

diagram.bpmn (7.4 KB)

Hey @cobalt,

you haven’t set “async before” on your service task. Hence all the service task run in one transaction. That’s why the error is not triggered. Make sure to mark the service task with async before in the properties panel in the Camunda Modeler. i think that should do the trick.

Kind regards
Nele

Hi Nele

I have had tried it with “async” as well on the service task but made no difference. Could this be a bug? I’ve setup a fresh blank spring project with nothing else in it and ran this multiple times, still facing the same issue. BpmnError is getting triggered, but the REST response simply is the 500 internal error unless I assign the BpmnError as a variable in the delegateExecution and access it to see if its an instanceof an exception and trigger an appropriate ResponseEntity logic based on that.

public ResponseEntity create() throws URISyntaxException {
    ProcessInstanceWithVariables instance = processEngine
            .getRuntimeService()
            .createProcessInstanceByKey("BPMNKey")
            .executeWithVariablesInReturn();


    if (instance.getVariables().getValueTyped("EntityDTO").getValue() instanceof EntityDTO) {
        return ResponseEntity.ok().body(instance.getVariables().getValueTyped("EntityDTO").getValue());
    }
    return ResponseEntity.status(400).body((EntityDTO) instance.getVariables().getValueTyped("EntityDTO").getValue());
}

If I dont use this hack the result is a standard:

{
“timestamp”: “2021-04-08T10:15:28.163+00:00”,
“status”: 500,
“error”: “Internal Server Error”,
“message”: “”,
“path”: “/api/v1/endpoint”
}

If I pass on the BpmnError() as a variable and check it using the above, its only then I get to see the error code and error message assigned to the BpmnError.

{
“cause”: null,
“stackTrace”: [
],
“errorCode”: “9000”,
“message”: “We have a problem”,
“suppressed”: [],
“localizedMessage”: “We have a problem”
}

Many thanks

Hi @cobalt

I’ve created a simple example that might help with understanding an approach that could help you achieve what you’re looking for.
Camunda makes a rest call and after evaluating the response code will either trigger an error event or it will continue the process.

1 Like

Hi @Niall

Thank you for the example. This is exactly what I have done in my code as well. BpmnError does get triggered but the problem is on the rest client side, typically I was expecting BpmnError to give me a detailed rest response on the client side so there on I could display this on the react frontend but all I get is the standard 500 internal error. The only way I would get that error is by setting BpmnError as a DelegateExecution variable and write a custom global error handler that looks for that value in so it can be processed and passed on to the frontend, unless there is a better way of handling this issue which I have missed.

My issue wasn’t that BpmnError is not being triggered but rather, I cant get the error codes and messages as a result.

I added a rest endpoint to your code and pretty much ended up in the same place as before, that is the 500 internal error scenario, but the code perfectly works fine within the Camunda Tasklist environment.

@RestController
@RequestMapping("/api/v1")
public class MyRestController {

@Autowired
private ProcessEngine processEngine;

@GetMapping("/get")
public ResponseEntity get() {

    Map<String, Object> variables = new HashMap<>();
    variables.put("repoName", "hello-world");
    variables.put("repoOwner", "octocat2");

    ProcessInstanceWithVariables instance = processEngine
            .getRuntimeService()
            .createProcessInstanceByKey("BPMN-Error-From-Rest-process")
            .setVariables(variables)
            .executeWithVariablesInReturn();

    String result = (String) instance.getVariables().getValueTyped("repoResponse").getValue();
    return ResponseEntity.ok().body(result);
}

}

Thanks