Controlling Event Flow and Handling Errors
Error handlers, not catch blocks
Mule 4 uses on-error-propagate (handle, then rethrow to the parent or HTTP listener) and on-error-continue (handle and return normally - whatever the handler produces becomes the response for an HTTP listener). Handlers attach to flows, to global configuration (defaultErrorHandler), and to try scopes. Matching is top-down against the type hierarchy MULE:ANY > namespace (HTTP:UNAUTHORIZED) > specific (HTTP:UNAUTHORIZED:TOKEN_EXPIRED). First match wins, so list specific types before broad ones; type="ANY" catches everything, and wildcards like HTTP:* are allowed.
The error object
error.description, error.detail, error.type, error.errorType.namespace, error.errorType.identifier, and error.childErrors (populated by scatter-gather) let you shape precise error responses.
Transactions and retries
A try scope can be transactional via transactionalAction (such as NONE or ALL), so local operations roll back when an error propagates out of the scope. An on-error-continue inside the scope swallows the error and therefore prevents the rollback. until-successful retries a processor on failure with a configured count and wait interval.
Flow control
choice takes one branch, scatter-gather runs all routes and fails if any fails, first-successful returns the first non-erroring route, async forks and discards the result, and raise-error throws a custom type. The Validation module (is-true, is-not-null, is-null) raises VALIDATION:* errors for guard clauses.
Traps
- Believing
on-error-continuesuppresses the response - it supplies one. - Expecting a policy or APIkit handler to fire before your flow's own handler; scope order decides.
- Handler order matters: a broad
on-error-propagate type="ANY"first makes later handlers dead code.
Rule of thumb
Use on-error-propagate when a global handler or a proper HTTP error status should win; use on-error-continue only when the flow can meaningfully keep going.