n8n Validation Expert
Complete guide to interpreting errors, validating workflows, and ensuring production readiness
Overview
This skill covers workflow validation, error interpretation, and production readiness. It includes a complete error catalog, validation profiles (minimal, runtime, ai-friendly, strict), auto-fix tools, error handling patterns, and pre-deployment checklists. Use this when encountering validation errors or preparing workflows for production.
Quick Reference
| Need | Tool/Action |
|---|---|
| Validate single node | validate_node() with profile |
| Validate full workflow | n8n_validate_workflow() |
| Auto-fix common issues | n8n_autofix_workflow() |
| Clean broken connections | cleanStaleConnections operation |
| Error handling setup | Error Trigger workflow |
Part 1: Validation Philosophy
The Iterative Process
Validation is NOT one-shot - expect multiple cycles:
Configure → Validate → Read Errors → Fix → Validate Again
↑ ↓
└────────── Repeat (2-3 times) ──────┘
Telemetry Insights:
- •Average: 23 seconds thinking about errors
- •Average: 58 seconds fixing them
- •Typical: 2-3 validation cycles per node
Validate Early, Validate Often
- •During Development: Use
minimalprofile for quick checks - •Before Testing: Use
runtimeprofile - •Before Deployment: Use
strictprofile - •After Template Deploy: Always validate imported workflows
Part 2: Error Severity Levels
Level 1: Errors (Must Fix)
Blocks workflow execution - Cannot activate workflow until resolved
| Error Type | Description | Example |
|---|---|---|
missing_required | Required field not provided | Missing channel name |
invalid_value | Value not in allowed options | Wrong operation type |
type_mismatch | Wrong data type | String instead of number |
invalid_reference | Referenced node doesn't exist | Typo in node name |
invalid_expression | Expression syntax error | Missing {{ }} wrapper |
invalid_connection | Connection to non-existent node | Deleted node still referenced |
Level 2: Warnings (Should Fix)
Doesn't block execution - Workflow can activate but may have issues
| Warning Type | Description |
|---|---|
best_practice | Recommended but not required |
deprecated | Using old API/feature |
performance | Potential performance issue |
security | Potential security concern |
missing_error_handling | No error workflow configured |
Level 3: Suggestions (Optional)
Nice to have - Improvements that could enhance workflow
- •Optimization opportunities
- •Alternative approaches
- •Documentation recommendations
Part 3: Complete Error Catalog
Authentication Errors
401 - Unauthorized
{
"status": 401,
"message": "Request failed with status code 401"
}
Causes:
- •Invalid or expired API key
- •Wrong credentials
- •Missing authentication header
- •OAuth token expired
Fixes:
- •Verify API key in credentials
- •Check if key was regenerated
- •Refresh OAuth connection
- •Verify account has required permissions
403 - Forbidden
{
"status": 403,
"message": "Forbidden - perhaps check your credentials"
}
Causes:
- •Valid credentials but insufficient permissions
- •IP not whitelisted
- •Account suspended
- •Resource access denied
Fixes:
- •Check API permissions/scopes
- •Verify IP whitelist settings
- •Review account status
- •Confirm resource access rights
Request Errors
400 - Bad Request
{
"status": 400,
"message": "Bad request - please check your parameters"
}
Causes:
- •Invalid parameter name or value
- •Malformed JSON body
- •Missing required parameters
- •Array not formatted correctly
Fixes:
- •Review API documentation
- •Validate JSON structure
- •Check parameter names/values
- •Use Array Format option for Query Parameters
404 - Not Found
{
"status": 404,
"message": "The resource you are requesting could not be found"
}
Causes:
- •Wrong endpoint URL
- •Resource deleted
- •ID doesn't exist
- •API version mismatch
Fixes:
- •Verify endpoint URL
- •Check if resource exists
- •Confirm ID is correct
- •Review API version
429 - Rate Limited
{
"status": 429,
"message": "The service is receiving too many requests from you"
}
Causes:
- •Too many requests in time window
- •Account rate limit exceeded
- •Concurrent request limit hit
Fixes:
- •Enable "Retry On Fail" with delays
- •Implement batching
- •Add delays between items
- •Upgrade API plan if needed
Configuration Errors
Missing Required Field
{
"type": "missing_required",
"property": "channel",
"message": "Channel name is required",
"fix": "Provide a channel name"
}
Fix Pattern:
// 1. Use get_node to see required fields // 2. Add the missing field config.channel = "#general"; // 3. Re-validate
Invalid Value
{
"type": "invalid_value",
"property": "operation",
"message": "Operation must be one of: post, update, delete",
"current": "send"
}
Fix Pattern:
// Check allowed values in error message or get_node config.operation = "post"; // Use valid value
Type Mismatch
{
"type": "type_mismatch",
"property": "limit",
"message": "Expected number, got string",
"current": "100"
}
Fix Pattern:
config.limit = 100; // Number, not "100" string
Expression Errors
Invalid Expression Syntax
{
"type": "invalid_expression",
"property": "text",
"message": "Invalid expression: $json.name",
"current": "$json.name"
}
Fix: Add ={{ }} wrapper:
config.text = "={{ $json.name }}";
Invalid Reference
{
"type": "invalid_reference",
"message": "Node 'HTTP Requets' does not exist"
}
Fix: Correct typo in node name:
// Wrong: $node['HTTP Requets'] // Correct: $node['HTTP Request']
Cannot Read Properties of Undefined
{
"message": "Cannot read properties of undefined (reading 'name')"
}
Causes:
- •Accessing property on undefined object
- •Previous node didn't run
- •Expression references non-existent field
- •Optional chaining not used
Fixes:
// Use optional chaining
{{ $json.user?.profile?.name }}
// Provide default
{{ $json.name ?? 'default' }}
// Check node executed
{{ $("Previous Node").first()?.json?.field }}
Connection Errors
Database Connection Failed
{
"message": "Cannot connect to database"
}
Causes:
- •Wrong connection string
- •Database server down
- •Network/firewall issue
- •Credentials incorrect
Fixes:
- •Verify connection string
- •Check database server status
- •Test with database client (pgAdmin, etc.)
- •Verify network access
Webhook Not Reachable
{
"message": "Webhook URL not accessible"
}
Causes:
- •n8n not publicly accessible
- •Wrong webhook URL configured
- •Firewall blocking requests
- •SSL certificate issues
Fixes:
- •Use tunneling (ngrok) for local development
- •Verify public URL configuration
- •Check firewall rules
- •Verify SSL certificate
Part 4: Validation Profiles
| Profile | When to Use | What It Validates |
|---|---|---|
| minimal | Quick checks during editing | Required fields, basic structure |
| runtime | Pre-deployment (RECOMMENDED) | Required fields, types, allowed values |
| ai-friendly | AI-generated configs | Same as runtime, fewer false positives |
| strict | Production, critical workflows | Everything + best practices + security |
Usage
// Single node validation
validate_node({
nodeType: "nodes-base.slack",
config: { resource: "message", operation: "post" },
mode: "full",
profile: "runtime" // RECOMMENDED
})
// Full workflow validation
n8n_validate_workflow({
id: "workflow-id",
options: {
validateNodes: true,
validateConnections: true,
validateExpressions: true,
profile: "runtime"
}
})
Profile Selection Guide
Development → minimal (fast feedback)
↓
Testing → runtime (balanced)
↓
Production → strict (comprehensive)
AI-generated workflows → ai-friendly (reduces false positives)
Part 5: MCP Validation Tools
validate_node - Single Node Validation
validate_node({
nodeType: "nodes-base.slack",
config: {
resource: "message",
operation: "post",
channel: "#general",
text: "Hello!"
},
mode: "full", // full or minimal
profile: "runtime" // minimal, runtime, ai-friendly, strict
})
n8n_validate_workflow - Workflow Validation
n8n_validate_workflow({
id: "workflow-id",
options: {
validateNodes: true, // Validate node configurations
validateConnections: true, // Check connection integrity
validateExpressions: true, // Validate expression syntax
profile: "runtime"
}
})
n8n_autofix_workflow - Auto-fix Issues
// Preview fixes first (ALWAYS do this)
n8n_autofix_workflow({
id: "workflow-id",
applyFixes: false, // Preview mode
confidenceThreshold: "medium"
})
// Then apply if fixes look correct
n8n_autofix_workflow({
id: "workflow-id",
applyFixes: true
})
Available Fix Types
| Fix Type | What It Fixes |
|---|---|
expression-format | Missing = prefix in expressions |
typeversion-correction | Incorrect node typeVersion |
typeversion-upgrade | Upgrade to latest typeVersion |
error-output-config | Error output configuration |
node-type-correction | Node type mismatches |
webhook-missing-path | Missing webhook paths |
version-migration | v2.0+ migration issues |
Targeted Fix Application
// Only apply specific fix types
n8n_autofix_workflow({
id: "workflow-id",
applyFixes: true,
fixTypes: ["expression-format", "typeversion-upgrade"],
confidenceThreshold: "high" // Only high-confidence fixes
})
Part 6: Auto-Sanitization System
What It Does
Automatically fixes operator structure issues on ANY workflow update.
Runs when:
- •
n8n_create_workflow - •
n8n_update_partial_workflow - •Any workflow save operation
Binary Operators (Two Values)
Operators: equals, notEquals, contains, notContains, greaterThan, lessThan, startsWith, endsWith
Fix: Removes erroneous singleValue property
// Before (wrong)
{
"operation": "equals",
"singleValue": true // ❌ Wrong for binary operator
}
// After (auto-fixed)
{
"operation": "equals"
// singleValue removed ✅
}
Unary Operators (One Value)
Operators: isEmpty, isNotEmpty, true, false
Fix: Adds required singleValue: true
// Before (missing)
{
"operation": "isEmpty"
// Missing singleValue ❌
}
// After (auto-fixed)
{
"operation": "isEmpty",
"singleValue": true // ✅ Added
}
What Auto-Sanitization CANNOT Fix
| Issue | Solution |
|---|---|
| Broken connections | Use cleanStaleConnections operation |
| Branch count mismatches | Add missing connections manually |
| Paradoxical corrupt states | May require database intervention |
| Expression logic errors | Manual review required |
| Wrong node type entirely | Replace node manually |
Part 7: Common Node-Specific Errors
HTTP Request Node
| Error | Cause | Fix |
|---|---|---|
| "JSON parameter need to be valid JSON" | Malformed JSON body | Validate JSON structure |
| "Bad request - check parameters" | Invalid query params | Review API docs, check array format |
| 401/403 errors | Auth issues | Verify credentials and permissions |
| SSL certificate errors | Self-signed cert | Enable "Ignore SSL Issues" option |
Code Node
| Error | Cause | Fix |
|---|---|---|
| "Code doesn't return items properly" | Wrong return format | Return [{json: {...}}] |
| "A 'json' property isn't an object" | json property is primitive | Wrap in object |
| "Cannot find module" | External module not allowed | Check NODE_FUNCTION_ALLOW_EXTERNAL |
| "'import' may only appear at top level" | ES module syntax in CJS context | Use require() instead |
AI Agent Node
| Error | Cause | Fix |
|---|---|---|
| "Cannot read properties (reading 'message')" | Missing message field in input | Verify chat input schema |
| "Cannot read properties (reading 'content')" | Tool output format mismatch | Check tool return format |
| Model timeout | Request too complex | Reduce input size or simplify |
Database Nodes
| Error | Cause | Fix |
|---|---|---|
| "Connection refused" | Server not accessible | Check host/port, firewall |
| "Authentication failed" | Wrong credentials | Verify username/password |
| "Unknown column" | Column doesn't exist | Check table schema |
| "Duplicate entry" | Unique constraint violation | Handle duplicates in logic |
Part 8: Expression Validation
Common Expression Errors
| Error | Cause | Fix |
|---|---|---|
| Expression shows literal text | Missing {{ }} | Wrap in {{ }} |
| Empty result from webhook | Accessing root instead of body | Use $json.body.field |
| "Referenced node is unexecuted" | Node hasn't run | Ensure node is in execution path |
| "Cannot read properties of undefined" | Missing property | Use optional chaining ?. |
| Wrong data from $node | Item count mismatch | Use $("Node").first() |
Expression Validation Checklist
[ ] Expression wrapped in {{ }}
[ ] All variables have $ prefix ($json, $input, etc.)
[ ] Node names match exactly (case-sensitive)
[ ] Webhook data accessed via $json.body
[ ] Optional chaining used for nested access
[ ] Default values provided for optional fields
[ ] Referenced nodes exist and will execute
Debug Expressions
// Check what keys exist
{{ Object.keys($json) }}
// Verify node reference
{{ $("Previous Node").first()?.json ? 'OK' : 'FAILED' }}
// Check type
{{ typeof $json.field }}
// Full structure
{{ JSON.stringify($json, null, 2) }}
Part 9: Workflow-Level Validation
Structural Issues
Broken Connections
{
"error": "Connection from 'Transform' to 'NonExistent' - target node not found"
}
Fix:
n8n_update_partial_workflow({
id: "workflow-id",
operations: [{
type: "cleanStaleConnections"
}]
})
Circular Dependencies
{
"error": "Circular dependency detected: Node A → Node B → Node A"
}
Fix: Restructure workflow to break the loop. Use Wait node if polling needed.
Multiple Trigger Nodes
{
"warning": "Multiple trigger nodes found - only one will execute"
}
Fix: Remove extra triggers or split into separate workflows.
Disconnected Nodes
{
"warning": "Node 'Transform' is not connected to workflow flow"
}
Fix: Connect node to workflow or remove if unused.
Import/Export Issues
| Issue | Cause | Fix |
|---|---|---|
| Missing nodes after import | Community nodes not installed | Install required nodes |
| Credential errors | Credentials don't exist | Re-create credentials |
| Version mismatch | Workflow from newer n8n | Update n8n or use autofix |
| Invalid JSON | Corrupted export | Use JSON validator |
Part 10: Error Handling Patterns
Pattern 1: Error Workflow (Centralized Handler)
Create a dedicated error workflow for all failures:
┌─────────────────────────────────────────────────┐ │ Error Workflow: [System] Centralized Handler │ ├─────────────────────────────────────────────────┤ │ Error Trigger → Switch (by workflow name) │ │ ↓ ↓ │ │ Critical Non-Critical │ │ ↓ ↓ │ │ Slack @channel Log to Sheet │ └─────────────────────────────────────────────────┘
Error Data Available:
- •
execution.id- Execution ID - •
execution.url- Link to execution - •
execution.retryOf- If retry of failed execution - •
workflow.name- Failed workflow name - •
node.name- Failed node name - •
error.message- Error details
Pattern 2: Retry On Fail (Automatic Retries)
For transient failures (API timeouts, rate limits):
// Node settings
{
"retryOnFail": true,
"maxTries": 3, // 3-5 for APIs
"waitBetweenTries": 5000 // 5-10 seconds
}
Pattern 3: Continue On Error (Batch Processing)
For processing items where some may fail:
Set node "On Error" to "Continue (using Error Output)"
↓
┌───┴───┐
Success Error
↓ ↓
Process Log/Queue
for review
Pattern 4: Fallback LLM
For AI workflows with provider redundancy:
AI Agent (GPT-4)
↓
[Enable Fallback Model]
↓
Claude (backup)
Pattern 5: Polling for Async Tasks
For long-running operations:
Start Task → Loop (Wait → Check Status)
↓
Is Complete?
↓ ↓
Yes No
↓ ↓
Continue Wait & Retry
Part 11: v2.0+ Validation Changes
Breaking Changes to Watch
| Change | Impact | Migration |
|---|---|---|
| Start node removed | Old workflows break | Replace with Manual Trigger |
| Pyodide Python removed | Python Code nodes fail | Use Task Runners |
| MySQL/MariaDB removed | DB connections fail | Migrate to PostgreSQL |
| Task runners default ON | Code isolation | Update env settings if needed |
| Sub-workflow behavior | Parent receives different data | Test sub-workflow outputs |
| Config file permissions | 0600 required | Update file permissions |
Using the Migration Tool
- •Go to Settings → Migration Report (v1.121.0+)
- •Review issues by severity:
- •Critical: Will break workflows - fix first
- •Medium: May cause issues
- •Low: Recommendations
- •Fix workflow-level issues first
- •Then address instance-level issues
- •Test thoroughly before upgrading
Execute Sub-Workflow Changes
Before v2.0:
- •Could call workflows with only "Manual Trigger"
- •Parent received results before child completed
After v2.0:
- •Workflows need active trigger for sub-workflow calls
- •Parent correctly waits for child completion
- •Fix: Add appropriate trigger to sub-workflows
Part 12: Recovery Strategies
Strategy 1: Start Fresh
When: Configuration is severely broken
- •Note required fields from
get_node - •Create minimal valid configuration
- •Add features incrementally
- •Validate after each addition
Strategy 2: Binary Search Debug
When: Workflow validates but executes incorrectly
- •Remove half the nodes
- •Validate and test
- •If works → problem in removed nodes
- •If fails → problem in remaining nodes
- •Repeat until isolated
Strategy 3: Clean Stale Connections
When: "Node not found" errors
n8n_update_partial_workflow({
id: "workflow-id",
operations: [{
type: "cleanStaleConnections"
}]
})
Strategy 4: Auto-fix with Preview
When: Multiple validation errors
// Always preview first!
const preview = n8n_autofix_workflow({
id: "workflow-id",
applyFixes: false
});
// Review suggested fixes
console.log(preview.suggestedFixes);
// Apply if appropriate
n8n_autofix_workflow({
id: "workflow-id",
applyFixes: true
});
Strategy 5: Template Redeploy
When: Template workflow corrupted
// Redeploy fresh from template
n8n_deploy_template({
templateId: 123,
autoFix: true,
autoUpgradeVersions: true
});
Part 13: Pre-Deployment Checklist
Node Validation
- • All nodes validated with
runtimeprofile - • No missing required fields
- • All values within allowed options
- • Credentials configured and tested
Expression Validation
- • All expressions wrapped in
{{ }} - • Node references match exact names
- • Webhook data accessed via
$json.body - • Optional chaining for nested access
- • Default values for optional fields
Workflow Structure
- • No broken connections
- • No circular dependencies
- • Single trigger node (or intentional multi-trigger)
- • All nodes connected to flow
Error Handling
- • Error workflow configured
- • Critical nodes have retry logic
- • Batch processing handles individual failures
- • Fallbacks for external dependencies
Testing
- • Tested with sample data
- • Edge cases handled (empty, null, errors)
- • Rate limits considered
- • Large data volumes tested
Documentation
- • Node descriptions added
- • Workflow purpose documented
- • Credential requirements noted
Part 14: Best Practices
Do
- •Validate after every significant change
- •Read error messages completely - they contain fix guidance
- •Fix errors iteratively - one at a time
- •Use
runtimeprofile for pre-deployment - •Check
validfield before assuming success - •Trust auto-sanitization for operator issues
- •Use
get_nodewhen unclear about requirements - •Preview auto-fixes before applying
Don't
- •Skip validation before activation
- •Try to fix all errors at once - leads to new errors
- •Ignore error messages - they're specific for a reason
- •Use
strictduring development - too noisy - •Assume validation passed - always check result
- •Apply auto-fixes blindly - preview first
- •Deploy with unresolved errors
Validation Result Structure
{
"valid": false,
"errors": [
{
"type": "missing_required",
"property": "channel",
"message": "Channel name is required",
"fix": "Provide a channel name"
}
],
"warnings": [
{
"type": "best_practice",
"message": "Consider adding error handling"
}
],
"suggestions": [
{
"type": "optimization",
"message": "Consider batch operations for better performance"
}
]
}
Reading Results
// 1. Check valid field first
if (result.valid) {
// ✅ Configuration is valid - proceed
} else {
// ❌ Has errors - must fix before proceeding
}
// 2. Process errors (MUST fix)
result.errors.forEach(error => {
console.log(`Error: ${error.property} - ${error.message}`);
console.log(`Fix: ${error.fix}`);
});
// 3. Review warnings (SHOULD fix)
result.warnings.forEach(warning => {
console.log(`Warning: ${warning.message}`);
});
// 4. Consider suggestions (OPTIONAL)
result.suggestions.forEach(suggestion => {
console.log(`Suggestion: ${suggestion.message}`);
});
Resources
- •n8n Error Handling Docs
- •Expression Common Issues
- •HTTP Request Common Issues
- •v2.0 Migration Tool
- •n8n Community Forum
Last Updated: January 2026