Workflows can fail for many reasons: API downtime, invalid data, network issues, or bugs. Proper error handling ensures your workflows are resilient and can recover from failures gracefully.
Understanding Flow Failures
When a step in your workflow fails, the default behavior is to stop execution:
// From packages/shared/src/lib/automation/flow-run/execution/flow-execution.ts
export enum FlowRunStatus {
RUNNING = 'RUNNING' ,
SUCCEEDED = 'SUCCEEDED' ,
FAILED = 'FAILED' ,
PAUSED = 'PAUSED' ,
STOPPED = 'STOPPED'
}
A failed step causes the entire workflow to stop with status FAILED, and subsequent steps don’t execute.
Error Handling Options
Every action step in Activepieces supports error handling configuration:
// From packages/shared/src/lib/automation/flows/actions/action.ts
export const ActionErrorHandlingOptions = {
"continueOnFailure" : {
"value" : boolean // Continue flow even if step fails
},
"retryOnFailure" : {
"value" : boolean // Retry step on failure
}
}
Select a Step
Click on any action step in your workflow.
Open Error Handling
In the step configuration panel, find the Error Handling section.
Enable Options
Toggle the options you need:
Continue on Failure : Flow continues even if this step fails
Retry on Failure : Automatically retry the step before failing
Continue on Failure
When enabled, the workflow continues executing even if the step fails:
// From packages/server/engine/test/handler/flow-error-handling.test.ts
{
"name" : "risky_operation" ,
"type" : "CODE" ,
"settings" : {
"sourceCode" : {
"code" : "export const code = async () => { throw new Error('Intentional error'); }"
},
"errorHandlingOptions" : {
"continueOnFailure" : {
"value" : true // Workflow continues
},
"retryOnFailure" : {
"value" : false
}
}
}
}
// Result:
{
"verdict" : {
"status" : "RUNNING" // Flow continues!
},
"steps" : {
"risky_operation" : {
"status" : "FAILED" ,
"errorMessage" : "Custom Runtime Error"
}
}
}
When to Use
Optional Operations Non-critical steps like logging, analytics, or notifications.
Fallback Logic When you have alternative steps to handle failures.
Best Effort Operations that should try but not block the workflow.
Parallel Operations When processing multiple items and some can fail.
Example: Optional Notification
{
"name" : "send_slack_notification" ,
"type" : "PIECE" ,
"settings" : {
"pieceName" : "@activepieces/piece-slack" ,
"actionName" : "send_message" ,
"input" : {
"channel" : "#notifications" ,
"text" : "Order processed: {{ trigger.orderId }}"
},
"errorHandlingOptions" : {
"continueOnFailure" : {
"value" : true // Don't fail workflow if Slack is down
}
}
},
"nextAction" : {
"name" : "update_database" , // This still runs even if Slack fails
"type" : "PIECE" ,
"settings" : { /* ... */ }
}
}
Retry on Failure
Automatically retry a step before marking it as failed:
{
"name" : "api_call" ,
"type" : "PIECE" ,
"settings" : {
"pieceName" : "@activepieces/piece-http" ,
"actionName" : "send_request" ,
"input" : {
"method" : "GET" ,
"url" : "https://api.example.com/data"
},
"errorHandlingOptions" : {
"retryOnFailure" : {
"value" : true // Retry on failure
}
}
}
}
Retries use exponential backoff to avoid overwhelming failing services.
When to Use
API calls that might fail due to temporary network issues. // HTTP requests, webhooks, external API calls
{
"errorHandlingOptions" : {
"retryOnFailure" : { "value" : true }
}
}
Services that might return rate limit errors. // APIs with rate limits
{
"pieceName" : "@activepieces/piece-openai" ,
"errorHandlingOptions" : {
"retryOnFailure" : { "value" : true }
}
}
Database queries that might face temporary connection issues. // Database connections
{
"pieceName" : "@activepieces/piece-postgresql" ,
"errorHandlingOptions" : {
"retryOnFailure" : { "value" : true }
}
}
File uploads or downloads that might be interrupted. // File operations
{
"actionName" : "upload_file" ,
"errorHandlingOptions" : {
"retryOnFailure" : { "value" : true }
}
}
Combining Error Handling Options
You can enable both options for maximum resilience:
{
"name" : "best_effort_api_call" ,
"type" : "PIECE" ,
"settings" : {
"pieceName" : "@activepieces/piece-http" ,
"actionName" : "send_request" ,
"errorHandlingOptions" : {
"retryOnFailure" : {
"value" : true // Try multiple times
},
"continueOnFailure" : {
"value" : true // But don't block workflow if all retries fail
}
}
}
}
Error Detection Patterns
Check Step Status
In subsequent steps, check if a previous step failed:
{
"name" : "check_previous_step" ,
"type" : "ROUTER" ,
"settings" : {
"conditions" : [[
{
"firstValue" : "{{ api_call.status }}" ,
"operator" : "TEXT_EXACTLY_MATCHES" ,
"secondValue" : "SUCCEEDED"
}
]]
},
"children" : [
// Branch 1: API succeeded
{
"name" : "process_data" ,
"settings" : {
"input" : {
"data" : "{{ api_call.body }}"
}
}
},
// Branch 2: API failed, use fallback
{
"name" : "use_cached_data" ,
"settings" : {
"input" : {
"data" : "{{ cached_data.output }}"
}
}
}
]
}
Handle Missing Data
Use null coalescing for safe data access:
{
"input" : {
// Provide defaults if step failed
"userData" : "{{ get_user.body ?? { name: 'Unknown', email: 'none' } }}" ,
"count" : "{{ fetch_count.output ?? 0 }}"
}
}
Error Notification Patterns
Send Alert on Failure
{
"name" : "critical_operation" ,
"type" : "PIECE" ,
"settings" : { /* ... */ },
"nextAction" : {
"name" : "check_if_failed" ,
"type" : "ROUTER" ,
"settings" : {
"conditions" : [[
{
"firstValue" : "{{ critical_operation.status }}" ,
"operator" : "TEXT_EXACTLY_MATCHES" ,
"secondValue" : "FAILED"
}
]]
},
"children" : [
// Send alert if failed
{
"name" : "send_alert" ,
"type" : "PIECE" ,
"settings" : {
"pieceName" : "@activepieces/piece-gmail" ,
"actionName" : "send_email" ,
"input" : {
"to" : "admin@example.com" ,
"subject" : "Critical Operation Failed" ,
"body" : "Error: {{ critical_operation.errorMessage }}"
}
}
},
// Continue normally if succeeded
null
]
}
}
Log All Errors
Create a dedicated error logging step:
{
"name" : "log_errors" ,
"type" : "CODE" ,
"settings" : {
"sourceCode" : {
"code" : `
export const code = async (inputs) => {
const errors = [];
// Check each step for failures
for (const [stepName, stepData] of Object.entries(inputs.steps)) {
if (stepData.status === 'FAILED') {
errors.push({
step: stepName,
error: stepData.errorMessage,
timestamp: new Date().toISOString()
});
}
}
// Log to external service
if (errors.length > 0) {
await fetch('https://logging.example.com/errors', {
method: 'POST',
body: JSON.stringify({ flowId: inputs.flowId, errors })
});
}
return errors;
};
`
},
"input" : {
"steps" : "{{ $steps }}" , // All step results
"flowId" : "{{ $flow.id }}"
}
}
}
Flow-Level Error Handling
// From packages/shared/src/lib/automation/flow-run/flow-run.ts
export type FlowRun = {
status : FlowRunStatus ,
steps : Record < string , StepOutput >,
failedStep ?: {
name : string ,
displayName : string ,
message : string
}
}
When a flow fails, you can see which step caused the failure:
{
"status" : "FAILED" ,
"failedStep" : {
"name" : "send_http" ,
"displayName" : "Send HTTP Request" ,
"message" : "Request failed with status 404"
}
}
Retry Entire Flow
// From packages/shared/src/lib/automation/flow-run/flow-run.ts
export enum FlowRetryStrategy {
ON_LATEST_VERSION = 'ON_LATEST_VERSION' , // Retry with latest flow version
FROM_FAILED_STEP = 'FROM_FAILED_STEP' // Resume from failed step
}
Manual Retry
Automatic Retry
From the flow runs page, click Retry on a failed run.
Configure automatic retries at the flow level (coming in future versions).
Error Handling in Loops
When a step fails inside a loop:
// From packages/server/engine/test/handler/flow-looping.test.ts
{
"name" : "bulk_process" ,
"type" : "LOOP_ON_ITEMS" ,
"settings" : {
"items" : "{{ [4, 5, 6] }}"
},
"firstLoopAction" : {
"name" : "process_item" ,
"type" : "CODE" ,
"settings" : {
"sourceCode" : {
"code" : "export const code = async () => { throw new Error('Failed'); }"
},
"errorHandlingOptions" : {
"continueOnFailure" : {
"value" : false // Stop loop on first failure
}
}
}
}
}
// Result: Loop stops at first iteration
{
"output" : {
"iterations" : [
{
"index" : 1 ,
"item" : 4 ,
"process_item" : {
"status" : "FAILED" ,
"errorMessage" : "Failed"
}
}
],
"index" : 1 ,
"item" : 4
}
}
Continue Loop on Errors
To process all items even if some fail:
{
"firstLoopAction" : {
"name" : "process_item" ,
"settings" : {
"errorHandlingOptions" : {
"continueOnFailure" : {
"value" : true // Continue with next iteration
}
}
}
}
}
Best Practices
Enable Retries for External APIs
Always enable retry for external API calls that might be temporarily unavailable. {
"errorHandlingOptions" : {
"retryOnFailure" : { "value" : true }
}
}
Use Continue on Failure Sparingly
Only enable for truly optional steps. Critical operations should fail the workflow. // Good: Optional analytics
{ "continueOnFailure" : true }
// Bad: Critical database update
{ "continueOnFailure" : false }
Check data validity before expensive operations. {
"name" : "validate_input" ,
"type" : "CODE" ,
"settings" : {
"sourceCode" : {
"code" : `
export const code = async (inputs) => {
if (!inputs.email || !inputs.email.includes('@')) {
throw new Error('Invalid email format');
}
return inputs;
};
`
}
}
}
Create a logging step that runs even on failures. {
"name" : "log_execution" ,
"errorHandlingOptions" : {
"continueOnFailure" : { "value" : true }
}
}
Test your workflows with:
Invalid data
Network timeouts
API errors
Missing required fields
Common Error Scenarios
HTTP 404 Errors
// From packages/server/engine/test/handler/flow-error-handling.test.ts
{
"send_http" : {
"status" : "FAILED" ,
"errorMessage" : JSON . stringify ({
"response" : {
"status" : 404 ,
"body" : {
"statusCode" : 404 ,
"error" : "Not Found" ,
"message" : "Route not found"
}
}
}, null , 2 )
}
}
Runtime Errors in Code
{
"runtime" : {
"status" : "FAILED" ,
"errorMessage" : "Custom Runtime Error: Cannot read property 'name' of undefined"
}
}
Connection Errors
{
"database_query" : {
"status" : "FAILED" ,
"errorMessage" : "Connection timeout: Could not connect to database"
}
}
Debugging Failed Runs
View Run History
Navigate to the Runs tab to see all executions.
Click Failed Run
Click on a run with status FAILED.
Identify Failed Step
The failed step is highlighted with error details.
Review Error Message
Read the error message to understand what went wrong.
Check Step Input
Verify the input data that caused the failure.
Fix and Retry
Update the flow or data, then retry the run.
Next Steps
Debugging Learn how to debug workflows
Monitoring Monitor workflow health
Loops & Branches Handle errors in control flow
Best Practices Build resilient workflows