Start with a failure model, not a catch-all fault
Reliable error handling begins by deciding what kind of failure happened. A single generic fault path usually retries the wrong things, hides business problems, and gives support teams too little information.
- Validation failureThe request is structurally valid, but one or more values are not acceptable.
- Business rejectionThe receiving system understood the request and deliberately rejected the operation.
- Temporary dependency failureA timeout, rate limit, or short outage means the same operation may succeed later.
- Permanent technical failureAuthentication, permissions, configuration, or an incompatible contract requires intervention.
- Unknown failureThe response does not fit a known category and must be preserved for investigation.
An error message explains what happened. An error contract tells the integration what to do next.
Define one predictable error contract
Translate vendor-specific payloads into a small internal structure. Every flow can then make decisions without knowing every possible response format.
{
"code": "CUSTOMER_NOT_FOUND",
"message": "No customer matched the supplied identifier.",
"category": "business",
"retryable": false,
"httpStatus": 404,
"correlationId": "req-8d41c6",
"source": "customer-api",
"details": {
"identifierType": "customerNumber"
}
}
Use it in switches, routes, monitoring, and support documentation.
Make it useful for an operator without exposing secrets.
Do not force every consumer to guess from an HTTP status.
Carry the same identifier through logs, API calls, and incidents.
The normalized contract should stay stable. Preserve the original response in protected logs when deeper investigation is required.
Choose the action by failure type
A compact decision table turns error handling into an operational policy instead of a collection of local guesses.
| Failure | Typical signal | Default action | Owner |
|---|---|---|---|
| Validation | 400 + field details | Reject and return a clear response | Calling system |
| Business | Known business code | Stop and route to business handling | Process owner |
| Temporary | 408, 429, 502, 503, 504 | Retry with limits and backoff | Integration |
| Permanent | 401, 403, invalid contract | Stop, alert, and correct configuration | Platform team |
| Unknown | Unrecognized payload | Stop safely and preserve evidence | Support |
Some APIs return business failures with HTTP 200, while others return a generic 500 for permanent validation problems. Inspect the documented payload as well.
Retry safely without creating duplicates
A retry is a second execution of the same business operation. It is only safe when the receiver can recognize that the operation has already been accepted.
- 1Create an idempotency key
Use a stable business identifier or generated submission ID, not the current timestamp.
- 2Send the key on every attempt
Keep it unchanged across retries so the receiver can return the original outcome.
- 3Use bounded exponential backoff
Wait longer between attempts and stop after a defined time or attempt count.
- 4Record the final state
Distinguish succeeded, exhausted, cancelled, and manually resolved operations.
- Retry timeouts and rate limits
- Respect a Retry-After header
- Keep one correlation ID
- Make retry limits visible
- Retrying all 4xx responses
- Generating a new business ID
- Infinite immediate retries
- Hiding exhausted operations
Idempotency-Key: order-56021351031024
X-Correlation-Id: req-8d41c6
X-Retry-Attempt: 2
Log the information that shortens investigation time
Useful logs connect the business operation, integration instance, request, dependency, and final decision. More text is not automatically better.
Search one value across every system.
Find the real order, customer, or task.
Aggregate recurring failure patterns.
Know whether the flow retried, stopped, or routed.
- Always include
- Timestamp, environment, integration name, instance ID, correlation ID, operation, source, normalized error code, and chosen action.
- Include when safe
- Non-sensitive identifiers, response status, retry count, elapsed time, and a sanitized payload fragment.
- Never include
- Passwords, access tokens, full personal data, card information, or unfiltered request and response bodies.
{
"event": "dependency-call-failed",
"integration": "Create_Customer",
"instanceId": "oic-19284751",
"correlationId": "req-8d41c6",
"businessKey": "customer-10442",
"errorCode": "DEPENDENCY_TIMEOUT",
"retryAttempt": 2,
"decision": "retry",
"elapsedMs": 30118
}
Design the Oracle Integration Cloud fault flow
Keep classification near the failing invoke, then route normalized faults to one shared handling scope. This avoids copying slightly different retry and logging logic throughout the integration.
Transport and timeout faults+
Classify connection failures, timeouts, and supported 5xx responses as temporary only when the operation is idempotent.
- Capture the endpoint and elapsed time
- Increment the retry attempt
- Apply bounded backoff
Known business faults+
Map documented codes into stable internal codes and route them to the correct business outcome without retrying.
- Preserve the external code
- Create a readable business message
- Return or store the expected status
Unknown faults+
Fail safely, store sanitized evidence, and alert support. Do not convert unknown failures into success or retry indefinitely.
- Use a generic internal code
- Keep the correlation ID visible
- Raise an actionable notification
fn:contains(
fn:lower-case(fn:string($Fault/ics:fault/ics:details)),
'timeout'
)
or fn:contains(
fn:lower-case(fn:string($Fault/ics:fault/ics:details)),
'service unavailable'
)
Give operations a small runbook
The error flow is incomplete until someone knows what to do when an alert arrives. Keep the first response short, ordered, and connected to the information in the log.
Search by correlation ID and confirm the affected business key.
Check the normalized error code, dependency status, and retry history.
Retry safely, correct data, fix configuration, or escalate to the dependency owner.
Record the resolution and update the classifier when the failure pattern was new.
Repeated manual classifications are a signal that the normalized error catalog or automated routing should be expanded.
Production readiness checklist
Keep external payloads at the boundary and let the rest of the integration work with one stable error contract.