Create incident and stop process flow

@cachescrubber you can update your code to something like this and the process will suspend as expected

    @Override
    public void execute(DelegateExecution execution) throws Exception {
        
       String id = execution.getProcessInstanceId();
        
        try {
            Object dog = execution.getVariable("dog");
            if (dog == null) {
                throw new RuntimeException("WHAT!!?");
            }
        } catch (RuntimeException e) {
            execution.createIncident("executeInternal", "ProcessVariableDoesNotExist", e.getMessage());
            Context.getCommandContext().getTransactionContext().addTransactionListener(TransactionState.COMMITTED, commandContext -> {
                runtimeService.suspendProcessInstanceById(id);
            });
        }
    }

Note that this will suspend the process after the transaction is completed and committed. So this means if you had N tasks after your incident task, and those N tasks were all sync and part of the same transaction as the trask that through the incident, then those N tasks will complete, and after that the process instance will be suspended.

Also take a look at the getTransactionContext().rollback() + adding a listener using TransactionState.ROLLED_BACK. You might be able to do a listener for post roll back and then trigger a roll back + have your incident logged. That way you dont have the process continue past the task that started the incident. Just a idea, have not tested that. But you will also have to keep in mind the impacts of a roll back. In the example of the BPMN image above, a rollback would have caused the process to not start, and thus unable to create a incident. You are likely going to have to recreate the same logic as core camunda: Rollback, create incident on the task that the rollback rolled back to.