Error handling in OIC: scopes, fault handlers and resubmitting failed runs

How to design error handling in Oracle Integration Cloud: scope and global fault handlers, custom faults, resubmitting failed runs and safe reruns.

InstanceHubPublished 17 Oct 20268 min read

An integration that works on the happy path is half finished. In a real project the target system is down for maintenance, a file has a bad row, a password expires, an API starts returning a field as text instead of a number. What separates a demo from something you can run in production is what the integration does at that moment: whether it stops cleanly, tells someone, keeps the data safe and can be run again once the cause is fixed.

Oracle Integration Cloud gives you the tools for this inside the designer. This guide walks through them in the order you would use them, with the design decisions that interviewers like to ask about.

Three questions to answer before you build

For every step that can fail, decide:

  1. Should the run stop or carry on? A failed payment posting should probably stop the run. One bad row in a file of thousands probably should not.
  2. Who needs to know? Nobody, a log line, an email to the support team, or a reply to the system that called you.
  3. Can it be run again safely? If the answer is no, a retry or a resubmit can create duplicates, which is often worse than the original failure.

The OIC features below are how you put those answers into the flow.

Scopes: the unit of error handling

A Scope is a box around a group of actions. It has its own variables and, more importantly, its own fault handler. When any action inside the scope fails, OIC stops running the scope's actions and runs the fault handler instead. After the handler finishes, the integration continues with whatever comes after the scope.

That last point is what makes scopes so useful. In a scheduled integration that loops over files, putting the per-file work inside a scope inside the loop means one bad file is handled and the loop moves on to the next one:

  • For Each file
    • Scope "ProcessFile"
      • read the file
      • insert the rows into the database
      • move the file to an archive folder
    • Fault handler of "ProcessFile"
      • move the file to an error folder
      • log the file name and the error message

Without the scope, the first bad file ends the run, every later file waits until tomorrow, and the bad file sits in the input folder to fail again.

What goes in a fault handler

Inside the handler you can read the fault's details: its code, the reason and the details text. Typical actions are:

  • a Logger line with the business key (order number, file name) and the error, so the activity stream explains what happened;
  • an invoke that moves or flags the failed record, so it is not picked up again blindly;
  • a Notification (email) to the people who can fix it;
  • a call to a shared error notifier integration, if your project has one, so every integration reports errors the same way.

Keep fault handlers simple. A handler that calls three systems can fail itself, and an error inside the handler is much harder to diagnose than the original one.

The global fault handler

Every integration also has a global fault handler, which catches any fault that no scope handled. Think of it as the last line of defence rather than the main design. It is the right place to:

  • log the failure with enough context to find it later;
  • notify support;
  • for a synchronous integration, send a proper error response back to the caller.

If an integration has no handling at all, OIC still records the failure, but the caller gets a generic error and nobody is told unless they are watching the monitoring pages.

Raising your own errors: Throw New Fault

Not every problem is a technical failure. An order with a quantity of zero, an invoice for a supplier that does not exist, a date in the future where none is allowed: the call to the target system might even succeed, but the data is wrong.

Throw New Fault lets you raise a business error yourself, with your own code and message, for example INVALID_QUANTITY: quantity must be greater than zero. It then behaves like any other fault: the nearest scope handler or the global handler catches it. This keeps validation in one place and makes the error message meaningful to whoever reads it.

Two related actions are worth knowing:

  • Re-throw Fault sends a fault you caught back up to the next level, for example after logging it in a scope handler, when the run really should stop.
  • Fault Return is for synchronous app driven integrations: it sends a defined fault response to the caller, such as an HTTP 400 with a clear message, instead of a generic server error.

Synchronous and asynchronous behave differently

This difference shapes your whole design, so it is worth stating plainly.

Synchronous integrations (a REST call that waits for an answer) report errors straight back to the caller. The caller decides whether to retry. These runs cannot be resubmitted from OIC afterwards, because the caller already has its answer. Your job is to return an error that tells the caller what went wrong and whether retrying makes sense.

Asynchronous integrations (scheduled runs, and app driven integrations that do not return a response) have nobody waiting. When they fail, OIC keeps the failed instance, and in many cases you can resubmit it from the monitoring pages once the cause is fixed. Your job is to make sure someone knows, and that resubmitting is safe.

Finding and resubmitting failed runs

In OIC Gen 3, the Observability section is where you investigate:

  1. Instances lists each run with its status. Search by integration name, time, or a business identifier such as an order number.
  2. Open an instance to see its activity stream: every step, its timing, the error at the failed step and, with Audit or Debug tracing, the messages before it.
  3. Errors lists only failed runs. For recoverable asynchronous runs you can select them and resubmit, one at a time or in bulk.

Business identifiers make the difference here. Marking a field such as the order number or file name as the primary identifier when you build the integration means support can find "order 1042" in seconds instead of scrolling through every run of the afternoon.

A resubmitted run starts again with the original input, so it only helps when the cause was outside the message: the target was down, a password had expired, a lookup was missing a value. If the input data itself is wrong, resubmitting fails the same way; the fix is upstream.

Make it safe to run twice

Retries, resubmits and reruns after a fix all mean the same data may arrive more than once. An integration that handles this is called idempotent, and it is the most underrated part of error handling.

Ways to get there:

  • Merge instead of insert. Database adapters offer a merge (insert or update on the key), so loading the same row twice updates it rather than failing or duplicating it.
  • Check before creating. Before creating a supplier or an invoice in the target, look it up by its business key.
  • Move processed files. A file that has been loaded moves to an archive folder; a failed one moves to an error folder. Neither is picked up again by accident.
  • Keep a watermark. For scheduled pulls, store the last successful run time in a schedule parameter and only fetch records changed after it. Update it only when the run succeeds.

A pattern that works

Put together, a robust scheduled integration usually looks like this:

  1. Read the watermark and fetch only new work.
  2. Loop over the items, with each item's processing inside a scope.
  3. In each scope's handler, log the business key and error, move or flag the item, and carry on.
  4. Count successes and failures as you go.
  5. At the end, send one summary notification if anything failed, rather than one email per row.
  6. Update the watermark only if the run completed.
  7. Keep a global fault handler for anything unexpected, which logs and notifies.

And a robust synchronous REST integration:

  1. Validate the input first and Throw New Fault with a clear message for bad data.
  2. Wrap calls to other systems in scopes, and decide in each handler whether to return an error or try an alternative.
  3. Use Fault Return so callers get a meaningful status and message.
  4. Set a business identifier so every call can be traced.

Common mistakes

  • Catching everything and carrying on silently. A handler with no log and no notification hides failures until a user complains.
  • Retrying non-idempotent calls. Posting an invoice twice is worse than failing once.
  • One giant scope. If the whole integration is one scope, you lose the ability to treat different failures differently.
  • Leaving Debug tracing on. It is invaluable while building and stores much more data than you need in production. Switch to Production or Audit level once the integration is stable.
  • No business identifiers. Every support conversation starts with "which run was it?".

Practise it

The fastest way to learn this is to break things on purpose. Build a scheduled integration that loads a CSV from FTP into a database table, then feed it a file with a duplicate key, rename a column, or change the database password, and watch what your handlers do. Then fix the cause and resubmit.

That needs an OIC instance with an FTP server and a database alongside it. Every InstanceHub OIC plan includes VBCS, an ATP database and FTP, so you can build exactly this flow, error folder included, and break it as often as you like.

See the OIC plans

Questions people ask

What is the difference between a scope fault handler and the global fault handler?

A scope fault handler catches errors from the actions inside that scope, and the integration continues after the scope. The global fault handler catches anything not handled elsewhere and runs at the level of the whole integration, typically to log, notify and end the run or return an error.

Can I resubmit a failed synchronous integration?

No. The caller already received the error, so it is the caller's job to retry. Resubmission from OIC's monitoring pages is for failed asynchronous runs, such as scheduled integrations.

When should I use Throw New Fault?

When the data is wrong for business reasons, such as a missing required value or an invalid quantity, even though no system has failed. It gives the error your own code and message and sends it to the nearest fault handler.

How do I stop one bad record from failing the whole batch?

Process each record or file inside a scope within the loop, and handle the fault in that scope's handler by logging it and moving or flagging the record. The loop then continues with the next item.