The Deluge throw Statement: Custom Exception Handling

Introducing the throw Statement in Deluge

Deluge now supports a throw statement, giving scripts a proper way to raise a custom exception the moment something goes wrong, rather than relying on workarounds to catch failures after the fact.

Why This Was Needed

Some failures in a Deluge script are easy to miss because the script itself still technically "succeeds" even when the underlying operation didn't. A classic example is a script using invokeUrl to call an external API: the call is marked successful the moment it's made, not once it actually succeeds. That means an API returning a 400 error, a rejected payload, or a silently failed transaction can all leave the script looking fine on the surface, while the business process behind it has actually broken. Handling this reliably before now meant a lot of manual, tedious workarounds.

What throw Does

throw lets you explicitly raise a custom exception the instant something goes wrong, whether that's an API returning an error, a business rule being violated, or a validation check failing. The script stops immediately at that point and hands control to the nearest matching catch block.

How throw and catch Work Together

The two are designed as a pair: throw raises the exception with whatever details you've defined, and catch picks it up and decides what to do next, whether that's retrying, notifying someone, or handling the situation gracefully. If no catch block exists to handle a thrown exception, the script simply terminates with the exception details, so a failure is never silently swallowed.

A simple example

If an order quantity is zero or negative, the script raises an exception, and the catch block handles it:

try
{
   if(orderQuantity <= 0)
   {
       throw "Invalid order quantity";
   }
   info "Order accepted.";
}
catch(e)
{
   info "Order failed: " + e;
   info "Line number: " + e.lineNo;
}

A more realistic business scenario

Consider a Deluge function pushing a new invoice to an external accounting service:

invoicePayload = Map();
invoicePayload.put("invoice_id", "INV-1042");
invoicePayload.put("amount", 2500);
invoicePayload.put("currency", "USD");

try
{
   response = invokeUrl
   [
       url : "https://api.example.com/invoices"
       type : POST
       parameters : invoicePayload
   ];
   if(response.get("status") != "success")
   {
       throw {
           "message" : "Invoice sync failed",
           "data" : response
       };
   }
   info "Invoice synced successfully.";
}
catch(e)
{
   info "Sync failed: " + e.message;
   info "API response: " + e.data;
   info "Line number: " + e.lineNo;
}

Here, the API response itself is attached to the exception as part of throw. When the accounting service rejects the invoice, the script stops immediately, and the calling catch block receives the full response for inspection, exactly the context needed to log, retry, or alert on the failure.

Rich Exception Details

Beyond a simple message, you can attach data of any Deluge type to an exception, which is what makes exceptions genuinely useful further down the line. Useful things to attach include:

  • The API response, for API-related failures
  • The record ID and current field values, for validation errors
  • The user input that triggered the issue, for form-level checks
  • Any custom object that helps the catch block understand exactly what went wrong

Re-throwing Exceptions

Sometimes a single catch block isn't the right place to fully resolve an exception. You can nest try-catch blocks inside one another, letting an inner catch do its own local handling, then re-throw the same exception up to an outer catch for further action, such as notifying a user or rolling back a change:

try
{
   try
   {
       // sync logic here
   }
   catch(e)
   {
       info "Sync failed: " + e.message;   // local logging
       throw e;  // re-throw to outer catch
   }
}
catch(e)
{
   // outer handler: notify the user, roll back, alert admin, etc.
}

The inner catch records the failure locally, while the outer catch handles the broader response, such as notifying someone or rolling back a change, without either block duplicating the other's logic.

Exception Propagation

If a function raises an exception without handling it itself, Deluge automatically passes that exception up to whichever script called the function, giving the calling script the opportunity to catch it. This is what makes genuinely reusable validation functions practical: you can write validation logic once, throw freely inside it, and let each calling script decide independently how it wants to respond to a failure.

Need help? 1 Cloud Consultants can help you build more robust Deluge scripts using proper exception handling with throw and catch, including reusable validation functions across your Zoho automations. Book a discovery call with 1 Cloud Consultants.