Catch Action Tool
What is a Catch Action?
A Catch Action is a special type of JavaScript action that only runs when the action directly before it fails with an error. Think of it as a safety net that catches problems and lets you handle them gracefully.
Why use Catch Actions?
- Prevent your entire tool from failing when one step goes wrong
- Provide helpful error messages instead of technical jargon
- Implement retry logic or fallback behaviors
- Transform errors into useful information
- Log errors for later troubleshooting
When to use Catch Actions:
- After API calls that might fail (network errors, rate limits, etc.)
- After complex JavaScript actions that could have runtime errors
- When calling external services that may be unreliable
- When you want to provide a default value if something fails
- When you need to log or report errors differently
How Catch Actions Work
The sequence:
- An action executes (API call, JavaScript, etc.)
- If the action succeeds → Continue to the next action, skip the Catch Action
- If the action fails → Run the Catch Action immediately after
- The Catch Action's output replaces the failed action's output
- Continue with remaining actions
Example flow:
Action 1: fetchUserData (API call)
Action 2: catchUserError (Catch Action) ← Only runs if Action 1 fails
Action 3: processData (JavaScript) ← Receives output from Action 1 OR Action 2
Scenario A - Success:
- Action 1 succeeds → Returns
{ userId: 123, name: "John" } - Action 2 is skipped
- Action 3 receives
{ userId: 123, name: "John" }
Scenario B - Failure:
- Action 1 fails → Returns
{ error: "Network timeout" } - Action 2 runs → Returns
{ userId: null, name: "Unknown", error: "Could not fetch user" } - Action 3 receives
{ userId: null, name: "Unknown", error: "Could not fetch user" }

Adding a Catch Action to Your Tool
Important: A Catch Action must come immediately after the action you want to protect.
- Add the action you want to protect (e.g., an API call)
- Click "Add Action" directly below it
- Select "Catch Action" as the action type
- Enter a descriptive action name (e.g.,
catchApiError,handleFetchError) - Write JavaScript code to handle the error
- Click "Add" or "Save"

Positioning matters:
✅ Correct:
Action 1: fetchData
Action 2: catchFetchError (Catch) ← Directly after Action 1
❌ Incorrect:
Action 1: fetchData
Action 2: processData
Action 3: catchFetchError (Catch) ← Too late! Won't catch Action 1 errors
Writing Catch Action Code
Catch Actions use JavaScript code, just like regular JavaScript actions. You have access to the same ctx object, which includes information about the error.
Accessing Error Information
When a Catch Action runs, ctx contains:
- The error message from the failed action
- All previous successful action outputs
- All tool inputs
ctxwhen an API call fails:
{
// Your tool inputs
userId: "12345",
// Previous successful actions
validateInput: { valid: true },
// The failed action's error
fetchUser: {
error: "Request failed with status code 404"
}
}
Pattern 1: Provide a Default Value
Return a sensible default when something fails:
async function main() {
return {
userId: ctx.userId,
name: "Unknown User",
email: "no-email@example.com",
status: "error",
message: "Could not fetch user data. Using default values."
};
}
Use case: When later actions need specific fields to exist, provide them with default values.
Pattern 2: Log Error and Return Graceful Message
Capture the technical error but return a user-friendly message:
async function main() {
const originalError = ctx.fetchUser?.error || "Unknown error occurred";
console.log("API call failed:", originalError);
return {
success: false,
message: "We couldn't retrieve the data right now. Please try again later.",
errorCode: "FETCH_FAILED"
};
}
Use case: When you want to hide technical details from end users but still log them for debugging.
Pattern 3: Retry Logic
Attempt to recover with alternative data or approach:
async function main() {
// If primary API failed, return instructions to try backup source
return {
useFallback: true,
fallbackSource: "cache",
message: "Primary source failed, use cached data instead"
};
}
Note: Catch Actions can't make API calls directly, but they can return instructions for later actions.
Pattern 4: Error Classification
Categorize errors and provide specific guidance:
async function main() {
const error = ctx.fetchData?.error || "";
let errorType;
let suggestion;
if (error.includes("404")) {
errorType = "NOT_FOUND";
suggestion = "The requested resource does not exist";
} else if (error.includes("401") || error.includes("403")) {
errorType = "UNAUTHORIZED";
suggestion = "Check your API credentials";
} else if (error.includes("timeout")) {
errorType = "TIMEOUT";
suggestion = "The service took too long to respond. Try again.";
} else if (error.includes("429")) {
errorType = "RATE_LIMIT";
suggestion = "Too many requests. Please wait before retrying.";
} else {
errorType = "UNKNOWN";
suggestion = "An unexpected error occurred";
}
return {
success: false,
errorType: errorType,
message: suggestion,
originalError: error
};
}
Use case: When different error types require different handling or user messages.
Pattern 5: Partial Recovery
Extract whatever valid data exists before the error:
async function main() {
return {
success: false,
partialData: ctx.previousAction?.partialResults || [],
failedAt: "fetchUser",
message: "Completed partial processing before error occurred"
};
}
Use case: When multi-step processes can preserve some results even if later steps fail.
Catch Action Examples
Example 1: Handling API Errors
Scenario: Fetch user data from an API that might return 404 or be down
// Action 1: fetchUser (API Action)
// GET https://api.example.com/users/{{userId}}
// Action 2: catchUserError (Catch Action)
async function main() {
console.log("User fetch failed, providing default user object");
return {
responseBody: {
userId: ctx.userId,
name: "Unknown User",
status: "not_found"
},
responseStatus: 200, // Fake success status for downstream actions
wasError: true
};
}
// Action 3: processUser (JavaScript Action)
// This action will receive either real user data or the default from catchUserError
async function main() {
const user = ctx.fetchUser.responseBody;
if (ctx.catchUserError?.wasError) {
return {
message: `User ${ctx.userId} not found. Created placeholder.`,
user: user
};
}
return {
message: `Successfully processed user ${user.name}`,
user: user
};
}
Example 2: Rate Limit Handling
Scenario: API might hit rate limits, need to handle gracefully
// Action 1: searchProducts (API Action)
// Action 2: catchRateLimit (Catch Action)
async function main() {
const error = ctx.searchProducts?.error || "";
if (error.includes("429") || error.includes("rate limit")) {
return {
responseBody: {
products: [],
message: "Search rate limit exceeded. Please try again in a few minutes.",
retryAfter: 60
},
responseStatus: 429,
isRateLimited: true
};
}
// Some other error
return {
responseBody: {
products: [],
message: "Search failed. Please try again later.",
error: error
},
responseStatus: 500
};
}
Example 3: Data Validation Errors
Scenario: JavaScript action validates data and might throw errors
// Action 1: validateAndProcess (JavaScript Action)
async function main() {
if (!ctx.email.includes('@')) {
throw new Error("Invalid email format");
}
if (ctx.age < 18) {
throw new Error("Must be 18 or older");
}
return {
valid: true,
data: { email: ctx.email, age: ctx.age }
};
}
// Action 2: catchValidationError (Catch Action)
async function main() {
const error = ctx.validateAndProcess?.error || "";
return {
valid: false,
errors: [error],
providedData: {
email: ctx.email,
age: ctx.age
},
message: "Validation failed: " + error
};
}
// Action 3: respondToUser (JavaScript Action)
async function main() {
if (!ctx.validateAndProcess.valid) {
return {
status: "error",
message: ctx.validateAndProcess.message
};
}
return {
status: "success",
message: "Data validated successfully"
};
}
Example 4: Chaining Multiple Catch Actions
Scenario: Multiple risky operations, each needs error handling
// Action 1: fetchUser (API Action)
// Action 2: catchUserError (Catch Action)
async function main() {
return {
responseBody: { userId: ctx.userId, name: "Default User" },
responseStatus: 200,
errorOccurred: true
};
}
// Action 3: fetchOrders (API Action) - Uses user data
// Action 4: catchOrdersError (Catch Action)
async function main() {
return {
responseBody: { orders: [] },
responseStatus: 200,
errorOccurred: true,
message: "Could not fetch orders, returning empty list"
};
}
// Action 5: formatReport (JavaScript Action)
async function main() {
const user = ctx.fetchUser.responseBody;
const orders = ctx.fetchOrders.responseBody.orders;
const warnings = [];
if (ctx.catchUserError?.errorOccurred) {
warnings.push("User data unavailable");
}
if (ctx.catchOrdersError?.errorOccurred) {
warnings.push("Orders data unavailable");
}
return {
report: {
user: user.name,
orderCount: orders.length,
warnings: warnings
}
};
}
Testing Catch Actions
Testing Catch Actions is tricky because you need the previous action to fail. Here's how to test them:
Method 1: Test in isolation
- Click the "Test" button at the bottom of the action editor
- Manually provide an error context:
{
"userId": "123",
"fetchUser": {
"error": "Request failed with status code 404"
}
}
- Click "Run Test"
- Verify the Catch Action returns appropriate error handling
Method 2: Test the full tool with bad inputs
- Use the "Test Tool" button
- Provide inputs you know will cause the previous action to fail
- Invalid API endpoint
- Non-existent user ID
- Invalid data that will fail validation
- Verify the Catch Action runs and handles the error correctly
Method 3: Temporarily break the previous action
- Temporarily modify the previous action to force an error
- Change API URL to an invalid endpoint
- Add code that throws an error:
throw new Error("Test error")
- Test the tool
- Verify the Catch Action runs
- Remember to restore the original action!
Troubleshooting Catch Actions
Problem: Catch Action never runs
- Cause: Previous action is not failing, or Catch Action is not positioned correctly
- Solution:
- Verify the Catch Action is immediately after the action it should catch
- Check that the previous action is actually failing (test it separately)
- Review the action order in your tool
Problem: Catch Action runs but tool still fails
- Cause: Catch Action itself has an error in its code
- Solution:
- Test the Catch Action code separately
- Add try/catch within the Catch Action:
async function main() {
try {
// Your error handling code
} catch (e) {
return { error: "Catch action failed: " + e.message };
}
}
Problem: Can't access error information
- Cause: The error structure might be different than expected
- Solution:
- Log the entire context to see what's available:
console.log("Full context:", JSON.stringify(ctx, null, 2));- Use safe access patterns:
const error = ctx.previousAction?.error || "Unknown error";
Problem: Later actions receive wrong data
- Cause: Catch Action's output structure doesn't match what later actions expect
- Solution:
- Make the Catch Action return the same structure as the successful action
- If original action returns
{ responseBody: {...}, responseStatus: 200 }, your Catch Action should too
Problem: Too many Catch Actions making code complex
- Cause: Trying to catch every possible error individually
- Solution:
- Only add Catch Actions for operations that commonly fail or are critical
- Combine error handling logic into fewer, more comprehensive Catch Actions
- Consider redesigning the tool if error handling becomes overwhelming
Catch Action Best Practices
1. Position correctly
Always place Catch Actions immediately after the action they protect:
✅ Action 1: apiCall
✅ Action 2: catchApiError
✅ Action 3: processResult
❌ Action 1: apiCall
❌ Action 2: processResult
❌ Action 3: catchApiError ← Too late
2. Return consistent structures
Match the output structure of the original action:
// If original API action returns:
// { responseBody: {...}, responseStatus: 200 }
// Your Catch Action should return:
async function main() {
return {
responseBody: { /* default or error data */ },
responseStatus: 500,
errorHandled: true
};
}
3. Log for debugging
Always log what error occurred:
async function main() {
const error = ctx.previousAction?.error || "Unknown error";
console.log("Error caught:", error);
return { /* your error handling */ };
}
4. Provide actionable messages
Give clear, helpful information:
// ❌ Bad
return { error: "It broke" };
// ✅ Good
return {
success: false,
message: "Could not fetch user data. The user ID may not exist or the service is temporarily unavailable.",
suggestion: "Verify the user ID and try again later."
};
5. Don't overuse
Only add Catch Actions where needed:
- After external API calls that might fail
- After complex JavaScript that might have runtime errors
- After critical operations where graceful degradation is important
- Not after every single action
6. Test both paths
Always test:
- Success path (Catch Action is skipped)
- Failure path (Catch Action runs)
7. Document error handling
Add comments explaining what errors you're handling and why:
async function main() {
// Handle 404 (not found) and 503 (service unavailable) errors
// by returning a cached default user object
return {
responseBody: { /* default user */ },
source: "cache"
};
}
Updated on: 03/11/2025
Thank you!