diff --git a/engine/src/main/java/io/camunda/zeebe/engine/processing/processinstance/ProcessInstanceModificationProcessor.java b/engine/src/main/java/io/camunda/zeebe/engine/processing/processinstance/ProcessInstanceModificationProcessor.java index 9f41b67c4aa6..9e81cc0399fb 100644 --- a/engine/src/main/java/io/camunda/zeebe/engine/processing/processinstance/ProcessInstanceModificationProcessor.java +++ b/engine/src/main/java/io/camunda/zeebe/engine/processing/processinstance/ProcessInstanceModificationProcessor.java @@ -572,7 +572,9 @@ private void terminateElement( } else if (elementType == BpmnElementType.CALL_ACTIVITY) { final var calledActivityElementInstance = elementInstanceState.getInstance(elementInstance.getCalledChildInstanceKey()); - terminateElement(calledActivityElementInstance, sideEffects); + if (calledActivityElementInstance != null && calledActivityElementInstance.canTerminate()) { + terminateElement(calledActivityElementInstance, sideEffects); + } } stateWriter.appendFollowUpEvent( diff --git a/engine/src/test/java/io/camunda/zeebe/engine/processing/processinstance/ModifyProcessInstanceTest.java b/engine/src/test/java/io/camunda/zeebe/engine/processing/processinstance/ModifyProcessInstanceTest.java index f89e24e959e5..81c394c7e314 100644 --- a/engine/src/test/java/io/camunda/zeebe/engine/processing/processinstance/ModifyProcessInstanceTest.java +++ b/engine/src/test/java/io/camunda/zeebe/engine/processing/processinstance/ModifyProcessInstanceTest.java @@ -17,6 +17,7 @@ import io.camunda.zeebe.model.bpmn.builder.SubProcessBuilder; import io.camunda.zeebe.protocol.record.Record; import io.camunda.zeebe.protocol.record.RecordType; +import io.camunda.zeebe.protocol.record.intent.IncidentIntent; import io.camunda.zeebe.protocol.record.intent.JobIntent; import io.camunda.zeebe.protocol.record.intent.ProcessInstanceIntent; import io.camunda.zeebe.protocol.record.intent.ProcessInstanceModificationIntent; @@ -850,6 +851,54 @@ public void shouldActivateParallelGateway() { .hasSize(4); } + @Test + public void verifyCallActivityWithIncidentInOutputMappingCanBeTerminated() { + final var child = Bpmn.createExecutableProcess("child").startEvent().endEvent().done(); + final var parent = + Bpmn.createExecutableProcess(PROCESS_ID) + .startEvent() + .callActivity("callActivity", c -> c.zeebeProcessId("child")) + .zeebeOutputExpression("x", "y") + .manualTask("task") + .endEvent() + .done(); + + ENGINE.deployment().withXmlResource(child).withXmlResource(parent).deploy(); + + final var processInstanceKey = ENGINE.processInstance().ofBpmnProcessId(PROCESS_ID).create(); + + final var callActivityElement = + RecordingExporter.processInstanceRecords(ProcessInstanceIntent.ELEMENT_ACTIVATED) + .withProcessInstanceKey(processInstanceKey) + .withElementId("callActivity") + .withElementType(BpmnElementType.CALL_ACTIVITY) + .getFirst(); + + Assertions.assertThat( + RecordingExporter.incidentRecords(IncidentIntent.CREATED) + .withProcessInstanceKey(processInstanceKey) + .getFirst()) + .extracting(r -> r.getValue().getElementId()) + .isEqualTo("callActivity"); + + ENGINE + .processInstance() + .withInstanceKey(processInstanceKey) + .modification() + .activateElement("task") + .terminateElement(callActivityElement.getKey()) + .modify(); + + verifyThatRootElementIsActivated(processInstanceKey, "task", BpmnElementType.MANUAL_TASK); + verifyThatProcessInstanceIsCompleted(processInstanceKey); + Assertions.assertThat( + RecordingExporter.processInstanceRecords(ProcessInstanceIntent.ELEMENT_TERMINATED) + .withProcessInstanceKey(processInstanceKey) + .withElementId(callActivityElement.getValue().getElementId()) + .exists()) + .isTrue(); + } + private static void verifyThatRootElementIsActivated( final long processInstanceKey, final String elementId, final BpmnElementType elementType) { verifyThatElementIsActivated(processInstanceKey, elementId, elementType, processInstanceKey);