Skip to main content

Error Handling

When validation fails during process execution, Stateway fires a BPMN error event with errorCode = "ValidationError". You can catch it with a boundary event on the failing activity, or let it propagate to put the instance in error state.

What Happens on Failure

  1. The activity's token does not advance. The activity stays in its current state (e.g., claimed for a userTask, executing for a serviceTask).
  2. A ValidationError event is dispatched.
  3. If a boundaryEvent with an errorEventDefinition is attached to the activity, it fires and the token follows that path.
  4. If no boundary event catches it, the instance moves to status: 'error' and the token is frozen.

Boundary Event Pattern

Attach a boundary error event to the failing activity:

<!-- At <bpmn:definitions> level — declare the error -->
<bpmn:error id="ValidationError" name="Validation Error" errorCode="ValidationError" />

<!-- The failing task -->
<bpmn:userTask id="approve" name="Approve Loan">
<!-- ... ioSpecification ... -->
</bpmn:userTask>

<!-- Boundary event catches ValidationError from "approve" -->
<bpmn:boundaryEvent id="approveValidationError" attachedToRef="approve" cancelActivity="true">
<bpmn:errorEventDefinition errorRef="ValidationError" />
<bpmn:outgoing>flow_to_correction</bpmn:outgoing>
</bpmn:boundaryEvent>

<!-- Route to a correction task -->
<bpmn:userTask id="correctApproval" name="Correct and Resubmit">
<bpmn:incoming>flow_to_correction</bpmn:incoming>
<bpmn:outgoing>flow_retry</bpmn:outgoing>
</bpmn:userTask>

<bpmn:sequenceFlow id="flow_to_correction" sourceRef="approveValidationError" targetRef="correctApproval" />
<bpmn:sequenceFlow id="flow_retry" sourceRef="correctApproval" targetRef="approve" />
tip

cancelActivity="true" (the default) cancels the original task when the boundary event fires. The token moves to the correction task; the original task is no longer active.

Error Context Variables

When validation fails (boundary event or not), Stateway injects error context into instance.variables:

VariableDescription
_validation.pathJSON path to the invalid field, e.g., "decision"
_validation.valueThe value that failed validation
_validation.expectedHuman-readable description of what was expected
_validation.errorsFull array of { path, value, message } error objects

You can use these in correction forms or gateway conditions:

<bpmn:exclusiveGateway id="checkError" name="What failed?" />
<bpmn:sequenceFlow sourceRef="checkError" targetRef="fixEnum"
condition="{{ _validation.path == 'decision' }}" />
<bpmn:sequenceFlow sourceRef="checkError" targetRef="fixObject"
condition="{{ _validation.path.startsWith('applicant') }}" />

Uncaught Errors — Instance Recovery

If no boundary event is present, the instance reaches status: 'error':

curl https://api.stateway.io/v1/instances/inst_01... \
-H "X-API-Key: sw_live_your_key"
{
"data": {
"id": "inst_01...",
"status": "error",
"variables": {
"_validation": {
"path": "decision",
"value": "APPROVED",
"expected": "one of: draft, approved, rejected"
}
}
}
}

After investigating and correcting the underlying issue, resume the instance:

curl -X POST https://api.stateway.io/v1/instances/inst_01.../resume \
-H "X-API-Key: sw_live_your_key"

The token restarts from the frozen activity. The user can then resubmit the corrected payload.

DataStore Not Found

When a DataStore lookup finds no matching instance and onNotFound="error" is set, the same ValidationError flow applies. The boundary event pattern works identically:

<bpmn:serviceTask id="lookup" name="Load Original Loan">
<bpmn:dataInputAssociation>
<bpmn:sourceRef>LoanStoreRef</bpmn:sourceRef>
<bpmn:targetRef>OriginalLoanRef</bpmn:targetRef>
</bpmn:dataInputAssociation>
</bpmn:serviceTask>

<bpmn:boundaryEvent id="loanNotFound" attachedToRef="lookup" cancelActivity="true">
<bpmn:errorEventDefinition errorRef="ValidationError" />
<bpmn:outgoing>flow_to_rejection</bpmn:outgoing>
</bpmn:boundaryEvent>

Use onNotFound="null" if you want execution to continue with the target variable set to null instead of raising an error.

Error Reference Declaration

Declare the bpmn:error element at the definitions level:

<bpmn:error id="ValidationError" name="Validation Error" errorCode="ValidationError" />

This is optional — Stateway matches on errorCode regardless — but recommended for BPMN modeler compatibility (Camunda Modeler, bpmn.io will render the error name in the diagram).

Summary

ScenarioResult
POST /instances with invalid variable400 response, instance not created
POST /tasks/:id/complete with invalid output400 response, task stays claimed
Invalid output from a service taskValidationError event fired
Boundary event presentToken follows the boundary path
No boundary eventInstance moves to error state
POST /instances/:id/resumeToken restarts from frozen activity