Skip to main content

Error handling

What fails a workflow

An execution ends as Failed when:

  • A node returns a failure result (NodeResult::fail(...)) — for example a required field missing, an Eloquent record not found, fail_on_error on an HTTP node hitting a 4xx/5xx, division by zero.
  • A node's handle() throws and its retry budget is exhausted (or it has none).
  • A Stop node runs with outcome: failure.

$execution->errorMessage carries the reason. Node-level detail is in the execution log — the failing node's row has status: error (or failed) and its error field set.

An execution ends as Cancelled (not an error) when a Stop node runs with outcome: success.

Failures inside a queued job (ExecuteWorkflowJob, ResumeExecutionJob) are captured as a Failed execution record — the job itself doesn't rethrow.

Retries

Any node can be given retry behaviour through its advanced settings (max_retries, retry_delay, retry_backoff). Retries only apply when handle() throws — a returned NodeResult::fail(...) is a deliberate failure and is not retried.

Observing failures

$execution = Workflow::run('flag-large-orders', $payload);

if ($execution?->status === ExecutionStatus::Failed) {
Log::error("Workflow {$execution->workflowId} failed", [
'execution_id' => $execution->id,
'reason' => $execution->errorMessage,
]);
}

Or query after the fact:

app(ExecutionRepositoryContract::class)
->listByStatus(ExecutionStatus::Failed, limit: 100);

Hook workflow.finished to react to every terminal outcome centrally — see Hooks.

Exceptions you might catch

ExceptionThrown byWhen
RuntimeExceptionExecutionManagerRunning/resuming an unknown workflow or execution id; resuming a non-suspended execution.
WorkflowAlreadyExistsExceptionWorkflow repocreate() with a duplicate id.
WorkflowNotFoundExceptionWorkflow repoupdate() on a missing workflow.
ExecutionNotFoundExceptionExecution repoupdate() on a missing execution.
BranchAlreadyOccupiedExceptionWorkflowDefinitionBuilderWiring a second edge onto a branch that's already taken.

Storage exceptions live under Qanna\WorkflowEngine\Storage\Exceptions.