Get Error Boundary Event from within DelegateExecution

Given the following process definitions:

Without boundary event:
image

With boundary event:
image

The above service task is implemented using a JavaDelegate, and when the underlying service spits an error, a BpmnError is thrown:

throw new BpmnError("TheErrorCode", "The Error Message");

Now, the problem arises when no Boundary Event was supplied, in the case of the first example (“Without boundary event”). In this situation, the process exits with the following message:

ENGINE-02042 Execution with id 'ServiceTask01' throws an error event with errorCode 'TheErrorCode', but no error handler was defined.

The information of the actual error disappears, which makes it fairly hard to find out why the task failed.

So what I want to do, is throw a BpmnError when a Boundary Event was supplied, but throw a regular exception when it was not. Eg:

if (hasErrorBoundary) {
    throw new SomeException("The Error Message");
} else {
    throw new BpmnError("TheErrorCode", "The Error Message");
}

In order to do this, I need to know whether an Error Boundary Event is supplied, and preferably, if it actually handles the thrown error code.

I found this code that seems to handle that in the engine itself:

Which not only provides information about any of the error boundaries, but also whether they handle the exception. However, I’m not getting the same result when I try this in my delegate:

DeploymentCache deploymentCache = Context.getProcessEngineConfiguration().getDeploymentCache();

ProcessDefinitionEntity processDefinitionEntity = deploymentCache.findDeployedProcessDefinitionById(delegateExecution.getProcessDefinitionId());

List<ErrorEventDefinition> errorEventDefinitions = processDefinitionEntity.getProperties().get(BpmnProperties.ERROR_EVENT_DEFINITIONS);

After which the “errorEventDefinitions” list is empty.
I’ve tried getting all properties, to see which ones are available:

Properties props = processDefinitionEntity.getProperties();
for (Map.Entry<String, Object> entry : props.toMap().entrySet()) {
	_logger.warning("Prop: " + entry.getKey());
}

Resulting in the following:

Prop: taskPriority
Prop: jobPriority
Prop: documentation

So that looks like it’s not even the right process definition, or I’m probably doing something wrong here.

Could anyone give some pointers on how to check whether a BpmnError would be handled by a boundary event, or that it would result in a “ENGINE-02042 - (…) no error handler was defined” error?

Hey @flyingpie,
so you want to determine in your delegate whether or not your model uses a BoundaryErrorEvent.
Assuming you can access the ServiceTask as BpmnElement, the following code allows you to retrieve the following code snippet allows you to check whether a BoundaryEvent exists and which task it is attached to. Subsequently you should check whether the BoundaryEvent contains an errorEventDefinition and if the task it is attached to corresponds to your ServiceTask. If both seems to be true, you should try to verify both error codes (both throw declaration and error code in the model).

I implemented it by parsing the XML directly and checking the underlying delegate’s referenced code. You can check the implementation here: BoundaryErrorChecker. Beware, that the retrieval of the definitions is based on the XML instead of using the API.

Cheers
Sascha

This is not necessary IMO. There is a setting in the process engine that defines that thrown BpmnError’s that are not “catched” in the model should be treated like ordinary exceptions, i.e. produce an incident. It’s sad that the default value of the setting is the other one, i.e. just consume the token. I think it’s because of backward compatibility. We change the setting in all of our projects.

Update: the setting is “enableExceptionsAfterUnhandledBpmnError”

`public static final String ERROR_EVENT_DEFINITIONS_PROPERTY = "errorEventDefinitions";`


    public static boolean isErrorEventDefinitionPresent(String errorCode, DelegateExecution execution) {
        ArrayList<?> errorEventDefinitions = (ArrayList<?>) ((ExecutionEntity) execution).getActivity().getProperty(ERROR_EVENT_DEFINITIONS_PROPERTY);
        if (Objects.nonNull(errorEventDefinitions)) {
            for (Object obj : errorEventDefinitions) {
                ErrorEventDefinition definition = (ErrorEventDefinition) obj;
                if (definition.getErrorCode().equals(errorCode)) {
                    return true;
                }
            }
        }
        return false;
    }