Learn how to set and manage workflow timeouts in n8n to prevent infinite runs, handle API call limits, and implement custom timeout logic with error handling and notifications.
Book a call with an Expert
Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.
In n8n, you can set timeouts for workflows using either the Timeout Workflow setting in the workflow settings panel or by using the Set node to establish a timeout within a specific workflow execution. This allows you to prevent workflows from running indefinitely, which is particularly useful for workflows that might get stuck in loops or for API calls that should time out after a certain period.
Step 1: Understanding Workflow Timeouts in n8n
Before diving into the implementation, it's important to understand what workflow timeouts are and why they're useful:
Step 2: Setting a Global Workflow Timeout
The most straightforward way to set a timeout for an entire workflow is through the workflow settings:
Here's how to access and set the workflow timeout:
// This is a conceptual representation, not actual code
// Navigate to: Workflows > [Your Workflow] > Settings
// Find "Timeout Workflow" and set a value in seconds
// Example: 300 (for 5 minutes)
Step 3: Setting Timeouts for HTTP Requests
For HTTP Request nodes specifically, you can set timeouts for individual requests:
Example configuration:
// In the HTTP Request node configuration
// Under Options:
{
"timeout": 30000 // 30 seconds in milliseconds
}
Step 4: Implementing Custom Timeouts Using the Set Node
For more advanced timeout handling, you can use the Set node to create custom timeout logic:
Here's a step-by-step implementation:
// In a Set node at the beginning of your workflow
// Name: Initialize Timeout
{
"variables": {
"startTime": "{{ Date.now() }}",
"timeoutMs": 60000 // 60 seconds timeout
}
}
// In a Set node before operations that might time out
// Name: Check Timeout
{
"variables": {
"currentTime": "{{ Date.now() }}",
"elapsedTime": "{{ $node['Check Timeout'].json.currentTime - $node['Initialize Timeout'].json.startTime }}",
"isTimedOut": "{{ $node['Check Timeout'].json.elapsedTime > $node['Initialize Timeout'].json.timeoutMs }}"
}
}
Then use an IF node to check the isTimedOut
variable and handle timeout scenarios appropriately.
Step 5: Implementing Timeouts with Error Handling
To create a more robust timeout implementation with proper error handling:
Here's an implementation example:
// Workflow structure:
// 1. Start Node
// 2. Set Node (Initialize Timeout)
// 3. Function Node (Check Timeout)
// 4. IF Node (Handle Timeout)
// - If true (timed out): Error Node
// - If false (not timed out): Continue workflow
// Function Node code to check timeout
function checkTimeout() {
const startTime = $input.item.json.startTime || Date.now();
const currentTime = Date.now();
const timeoutMs = $input.item.json.timeoutMs || 60000; // Default 60s
const elapsedTime = currentTime - startTime;
return {
startTime,
currentTime,
timeoutMs,
elapsedTime,
isTimedOut: elapsedTime > timeoutMs
};
}
// Return the result
return {json: checkTimeout()};
Step 6: Setting Timeouts for Specific Workflow Sections
If you need to set different timeouts for different parts of your workflow:
Example implementation:
// Set Node at the start of section 1
// Name: Section1Start
{
"variables": {
"section1StartTime": "{{ Date.now() }}",
"section1TimeoutMs": 30000 // 30 seconds timeout for section 1
}
}
// Check timeout before moving to section 2
// Function Node
function checkSection1Timeout() {
const startTime = $input.item.json.section1StartTime;
const currentTime = Date.now();
const timeoutMs = $input.item.json.section1TimeoutMs;
const elapsedTime = currentTime - startTime;
if (elapsedTime > timeoutMs) {
throw new Error('Section 1 timed out after ' + elapsedTime + 'ms');
}
return $input.item;
}
return {json: checkSection1Timeout()};
Step 7: Setting Timeouts for API Integrations
When working with external APIs, it's particularly important to set timeouts:
Implementation example:
// HTTP Request Node configuration
{
"url": "https://api.example.com/data",
"method": "GET",
"timeout": 15000, // 15 seconds timeout
"retry": {
"count": 3,
"maxTimeout": 10000
}
}
Step 8: Creating a Reusable Timeout Subworkflow
For more complex scenarios, you can create a reusable timeout mechanism:
Subworkflow implementation:
// In a separate workflow named "Timeout Checker"
// Input schema:
// {
// "timeoutMs": "number",
// "startTime": "number"
// }
// Function Node to check timeout
function checkTimeout() {
const startTime = $input.item.json.startTime;
const timeoutMs = $input.item.json.timeoutMs;
const currentTime = Date.now();
const elapsedTime = currentTime - startTime;
return {
startTime,
currentTime,
timeoutMs,
elapsedTime,
isTimedOut: elapsedTime > timeoutMs
};
}
return {json: checkTimeout()};
// Then in your main workflow, use Execute Workflow node
// to call this timeout checker
Step 9: Setting Up Timeout Notifications
To be notified when workflows time out:
Implementation example:
// After detecting a timeout in an IF node:
// Slack node configuration
{
"channel": "workflow-alerts",
"text": "Workflow '{{ $workflow.name }}' (ID: {{ $workflow.id }}) timed out after {{ $node['Check Timeout'].json.elapsedTime }}ms. Execution ID: {{ $execution.id }}",
"attachments": [
{
"color": "#ff0000",
"title": "Workflow Timeout Alert",
"text": "The workflow execution exceeded the maximum allowed time of {{ $node['Initialize Timeout'].json.timeoutMs }}ms."
}
]
}
Step 10: Monitoring and Optimizing Workflow Timeouts
After implementing timeouts, it's important to monitor and refine them:
Example monitoring approach:
// Set node to log execution time at end of workflow
// Name: LogExecutionTime
{
"variables": {
"endTime": "{{ Date.now() }}",
"totalExecutionTime": "{{ $node['LogExecutionTime'].json.endTime - $node['Initialize Timeout'].json.startTime }}",
"executionLog": {
"workflowId": "{{ $workflow.id }}",
"executionId": "{{ $execution.id }}",
"startTime": "{{ new Date($node['Initialize Timeout'].json.startTime).toISOString() }}",
"endTime": "{{ new Date($node['LogExecutionTime'].json.endTime).toISOString() }}",
"executionTimeMs": "{{ $node['LogExecutionTime'].json.totalExecutionTime }}",
"timeoutMs": "{{ $node['Initialize Timeout'].json.timeoutMs }}"
}
}
}
Step 11: Setting Timeouts in n8n Configuration
For system-wide timeout configuration, you can adjust n8n environment variables:
Example environment variable settings:
# In .env file or environment variables
N8N_PROCESS_TIMEOUT=300 # Global workflow timeout in seconds
N8N_QUEUE_BULL\_TIMEOUT=300000 # Queue processing timeout in milliseconds
Step 12: Handling Long-Running Operations with Timeouts
For workflows that need to process large datasets or perform long-running operations:
Implementation example:
// Function Node to process data with timeout awareness
function processBatchWithTimeout() {
const data = $input.item.json.data || [];
const batchSize = $input.item.json.batchSize || 100;
const startTime = $input.item.json.startTime || Date.now();
const timeoutMs = $input.item.json.timeoutMs || 60000;
const lastProcessedIndex = $input.item.json.lastProcessedIndex || 0;
let processedData = [];
let currentIndex = lastProcessedIndex;
const currentTime = Date.now();
// Process until we hit the end, the batch size, or timeout
while (
currentIndex < data.length &&
currentIndex < lastProcessedIndex + batchSize &&
Date.now() - startTime < timeoutMs \* 0.9 // Leave 10% buffer
) {
// Process item
processedData.push(processItem(data[currentIndex]));
currentIndex++;
}
const isComplete = currentIndex >= data.length;
const isTimedOut = Date.now() - startTime >= timeoutMs \* 0.9;
return {
processedBatch: processedData,
progress: {
lastProcessedIndex: currentIndex,
totalItems: data.length,
percentComplete: Math.round((currentIndex / data.length) \* 100),
isComplete,
isTimedOut
},
timeInfo: {
startTime,
currentTime: Date.now(),
elapsedMs: Date.now() - startTime,
timeoutMs
}
};
}
// Helper function to process a single item
function processItem(item) {
// Implement your processing logic here
return { ...item, processed: true };
}
return {json: processBatchWithTimeout()};
Step 13: Troubleshooting Timeout Issues
When you encounter timeout-related problems:
Troubleshooting approach:
// Function Node for diagnosing workflow performance
function diagnosePerformance() {
const executionSteps = $input.item.json.executionSteps || [];
const newStep = {
nodeId: $node.id,
timestamp: Date.now(),
memoryUsage: process.memoryUsage()
};
executionSteps.push(newStep);
// Calculate time between steps
if (executionSteps.length > 1) {
for (let i = 1; i < executionSteps.length; i++) {
executionSteps[i].timeSinceLastStepMs =
executionSteps[i].timestamp - executionSteps[i-1].timestamp;
}
}
return {
...($input.item.json),
executionSteps
};
}
return {json: diagnosePerformance()};
Step 14: Best Practices for Workflow Timeouts
Follow these best practices when implementing timeout logic:
Timeout best practices implementation:
// Documentation Node (Code node with doNotExecute: true)
/\*\*
- Workflow Timeout Configuration
- -----------------------------
- Overall workflow timeout: 5 minutes (300 seconds)
-
- Section-specific timeouts:
- - API data fetch: 30 seconds
- - Data processing: 2 minutes
- - Database updates: 1 minute
-
- Timeout handling:
- - On timeout, the workflow sends a notification to the #alerts channel
- - Partial results are saved to the database with a 'timed\_out' status
- - The workflow can be resumed from the last checkpoint
-
- Timeout values are set conservatively to account for:
- - Normal processing time (measured average + 50%)
- - Network latency (up to 5 seconds)
- - Service degradation (additional buffer)
\*/
Step 15: Advanced Timeout Patterns with n8n
For complex workflows, consider these advanced timeout patterns:
Implementation example:
// Function Node for advanced timeout handling
function handleAdvancedTimeout() {
const startTime = $input.item.json.startTime || Date.now();
const currentTime = Date.now();
const elapsedTime = currentTime - startTime;
// Define timeout levels
const softTimeoutMs = $input.item.json.softTimeoutMs || 45000; // 45 seconds
const hardTimeoutMs = $input.item.json.hardTimeoutMs || 60000; // 60 seconds
// Determine current status
const isSoftTimeout = elapsedTime > softTimeoutMs;
const isHardTimeout = elapsedTime > hardTimeoutMs;
// Prepare checkpoint data for possible resumption
const checkpointData = {
lastProcessedId: $input.item.json.lastProcessedId,
progress: $input.item.json.progress,
results: $input.item.json.results
};
// Return appropriate action based on timeout status
if (isHardTimeout) {
return {
action: "abort",
timeoutType: "hard",
elapsedTime,
checkpointData,
message: "Hard timeout reached, aborting execution"
};
} else if (isSoftTimeout) {
return {
action: "warn",
timeoutType: "soft",
elapsedTime,
checkpointData,
message: "Soft timeout reached, consider optimizing or aborting soon"
};
} else {
return {
action: "continue",
timeoutType: "none",
elapsedTime,
timeRemaining: {
untilSoftTimeout: softTimeoutMs - elapsedTime,
untilHardTimeout: hardTimeoutMs - elapsedTime
}
};
}
}
return {json: handleAdvancedTimeout()};
When it comes to serving you, we sweat the little things. That’s why our work makes a big impact.