# Error Catalog Comprehensive catalog of n8n validation errors with real examples and fixes. --- ## Error Types Overview Common validation errors by priority: | Error Type | Priority | Severity | Auto-Fix | |---|---|---|---| | missing_required | Highest | Error | ❌ | | invalid_value | High | Error | ❌ | | type_mismatch | Medium | Error | ❌ | | invalid_expression | Medium | Error | ❌ | | invalid_reference | Low | Error | ❌ | | operator_structure | Lowest | Not flagged | ✅ normalized on save | > **operator_structure** is no longer a validation finding (n8n-mcp ≥ 2.63.0). n8n derives unary/binary operators from the operator name and defaults the metadata, so both the raw and normalized shapes validate clean; the sanitizer just tidies the canonical form on save. See section 9. --- ## Errors (Must Fix) ### 1. missing_required **What it means**: Required field is not provided in node configuration **When it occurs**: - Creating new nodes without all required fields - Copying configurations between different operations - Switching operations that have different requirements **Most common validation error.** In practice the message reads **`Required property 'X' cannot be empty`** (e.g. `Required property 'URL' cannot be empty`, or `Code cannot be empty` for an empty Code node) — using the field's display name. This is a genuine error under every profile: n8n's own publish validation rejects these identically. It is *not* a false positive, even on templates where the field was stripped. #### Example 1: Slack Channel Missing **Error**: ```json { "type": "missing_required", "property": "channel", "message": "Channel name is required", "node": "Slack", "path": "parameters.channel" } ``` **Broken Configuration**: ```javascript { "resource": "message", "operation": "post" // Missing: channel } ``` **Fix**: ```javascript { "resource": "message", "operation": "post", "channel": "#general" // ✅ Added required field } ``` **How to identify required fields**: ```javascript // Use get_node to see what's required const info = get_node({ nodeType: "nodes-base.slack" }); // Check properties marked as "required": true ``` #### Example 2: HTTP Request Missing URL **Error**: ```json { "type": "missing_required", "property": "url", "message": "URL is required for HTTP Request", "node": "HTTP Request", "path": "parameters.url" } ``` **Broken Configuration**: ```javascript { "method": "GET", "authentication": "none" // Missing: url } ``` **Fix**: ```javascript { "method": "GET", "authentication": "none", "url": "https://api.example.com/data" // ✅ Added } ``` #### Example 3: Database Query Missing Connection **Error**: ```json { "type": "missing_required", "property": "query", "message": "SQL query is required", "node": "Postgres", "path": "parameters.query" } ``` **Broken Configuration**: ```javascript { "operation": "executeQuery" // Missing: query } ``` **Fix**: ```javascript { "operation": "executeQuery", "query": "SELECT * FROM users WHERE active = true" // ✅ Added } ``` #### Example 4: Conditional Fields **Error**: ```json { "type": "missing_required", "property": "body", "message": "Request body is required when sendBody is true", "node": "HTTP Request", "path": "parameters.body" } ``` **Broken Configuration**: ```javascript { "method": "POST", "url": "https://api.example.com/create", "sendBody": true // Missing: body (required when sendBody=true) } ``` **Fix**: ```javascript { "method": "POST", "url": "https://api.example.com/create", "sendBody": true, "body": { "contentType": "json", "content": { "name": "John", "email": "john@example.com" } } // ✅ Added conditional required field } ``` --- ### 2. invalid_value **What it means**: Provided value doesn't match allowed options or format **When it occurs**: - Using wrong enum value - Typos in operation names - Invalid format for specialized fields (emails, URLs, channels) **Second most common error** > **This fires only for an *explicitly wrong* value.** Omitting `operation` on a multi-resource node (Gmail, Telegram, Slack, Google Drive, Discord, Notion, …) no longer produces a fabricated "Invalid value for 'operation'" error (n8n-mcp ≥ 2.63.0) — the validator now resolves the correct per-resource default first. Expression values (`=...`) and dynamically-loaded option lists are also skipped. Under the `minimal` profile the operation enum check is not run at all. #### Example 1: Invalid Operation **Error**: ```json { "type": "invalid_value", "property": "operation", "message": "Operation must be one of: post, update, delete, get", "current": "send", "allowed": ["post", "update", "delete", "get"] } ``` **Broken Configuration**: ```javascript { "resource": "message", "operation": "send" // ❌ Invalid - should be "post" } ``` **Fix**: ```javascript { "resource": "message", "operation": "post" // ✅ Use valid operation } ``` #### Example 2: Invalid HTTP Method **Error**: ```json { "type": "invalid_value", "property": "method", "message": "Method must be one of: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS", "current": "FETCH", "allowed": ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"] } ``` **Broken Configuration**: ```javascript { "method": "FETCH", // ❌ Invalid "url": "https://api.example.com" } ``` **Fix**: ```javascript { "method": "GET", // ✅ Use valid HTTP method "url": "https://api.example.com" } ``` #### Example 3: Invalid Channel Format **Error**: ```json { "type": "invalid_value", "property": "channel", "message": "Channel name must start with # and be lowercase (e.g., #general)", "current": "General" } ``` **Broken Configuration**: ```javascript { "resource": "message", "operation": "post", "channel": "General" // ❌ Wrong format } ``` **Fix**: ```javascript { "resource": "message", "operation": "post", "channel": "#general" // ✅ Correct format } ``` #### Example 4: Invalid Enum with Case Sensitivity **Error**: ```json { "type": "invalid_value", "property": "resource", "message": "Resource must be one of: channel, message, user, file", "current": "Message", "allowed": ["channel", "message", "user", "file"] } ``` **Note**: Enums are case-sensitive! **Broken Configuration**: ```javascript { "resource": "Message", // ❌ Capital M "operation": "post" } ``` **Fix**: ```javascript { "resource": "message", // ✅ Lowercase "operation": "post" } ``` --- ### 3. type_mismatch **What it means**: Value is wrong data type (string instead of number, etc.) **When it occurs**: - Hardcoding values that should be numbers - Using expressions where literals are expected - JSON serialization issues **Common error** #### Example 1: String Instead of Number **Error**: ```json { "type": "type_mismatch", "property": "limit", "message": "Expected number, got string", "expected": "number", "current": "100" } ``` **Broken Configuration**: ```javascript { "operation": "executeQuery", "query": "SELECT * FROM users", "limit": "100" // ❌ String } ``` **Fix**: ```javascript { "operation": "executeQuery", "query": "SELECT * FROM users", "limit": 100 // ✅ Number } ``` #### Example 2: Number Instead of String **Error**: ```json { "type": "type_mismatch", "property": "channel", "message": "Expected string, got number", "expected": "string", "current": 12345 } ``` **Broken Configuration**: ```javascript { "resource": "message", "operation": "post", "channel": 12345 // ❌ Number (even if channel ID) } ``` **Fix**: ```javascript { "resource": "message", "operation": "post", "channel": "#general" // ✅ String (channel name, not ID) } ``` #### Example 3: Boolean as String **Error**: ```json { "type": "type_mismatch", "property": "sendHeaders", "message": "Expected boolean, got string", "expected": "boolean", "current": "true" } ``` **Broken Configuration**: ```javascript { "method": "GET", "url": "https://api.example.com", "sendHeaders": "true" // ❌ String "true" } ``` **Fix**: ```javascript { "method": "GET", "url": "https://api.example.com", "sendHeaders": true // ✅ Boolean true } ``` #### Example 4: Object Instead of Array **Error**: ```json { "type": "type_mismatch", "property": "tags", "message": "Expected array, got object", "expected": "array", "current": {"tag": "important"} } ``` **Broken Configuration**: ```javascript { "name": "New Channel", "tags": {"tag": "important"} // ❌ Object } ``` **Fix**: ```javascript { "name": "New Channel", "tags": ["important", "alerts"] // ✅ Array } ``` --- ### 4. invalid_expression **What it means**: n8n expression has syntax errors or invalid references **When it occurs**: - Missing `{{}}` around expressions - Typos in variable names - Referencing non-existent nodes or fields - Invalid JavaScript syntax in expressions **Moderately common** **Related**: See **n8n Expression Syntax** skill for comprehensive expression guidance > **Static validation catches expression *format*, not *resolution*.** `validate_node` / `validate_workflow` flag a missing `=` prefix (error) and a bare unwrapped `$json` reference (warning). They do **not** resolve node names or property paths *inside* an expression — a typo'd `$('Node')` reference or a missing property (Examples 2–4 below) surfaces at *execution* time, not during validation. Backtick template literals with `${...}` interpolation inside `{{ }}` are valid and are **not** flagged (n8n-mcp ≥ 2.63.0). #### Example 1: Missing `=` Prefix An expression field whose value contains `{{ }}` but doesn't start with `=` is treated as literal text — this is a real, static error. **Error**: ```json { "type": "error", "property": "assignments.assignments[0].value", "message": "Expression requires = prefix to be evaluated", "current": "{{ $json.name }}" } ``` **Broken Configuration**: ```javascript { "text": "{{ $json.name }}" // ❌ Has braces but no leading = } ``` **Fix**: ```javascript { "text": "={{ $json.name }}" // ✅ Leading = makes it an expression } ``` > A *bare* reference with no braces at all — `"$json.name"` — is a **warning**, not an error ("possible unwrapped expression"); n8n treats it as literal text, so wrap it as `={{ $json.name }}` if you meant to evaluate it. `n8n_autofix_workflow` can add the missing `=` for you. #### Example 2: Invalid Node Reference **Error**: ```json { "type": "invalid_expression", "property": "value", "message": "Referenced node 'HTTP Requets' does not exist", "current": "={{$node['HTTP Requets'].json.data}}" } ``` **Broken Configuration**: ```javascript { "field": "data", "value": "={{$node['HTTP Requets'].json.data}}" // ❌ Typo in node name } ``` **Fix**: ```javascript { "field": "data", "value": "={{$node['HTTP Request'].json.data}}" // ✅ Correct node name } ``` #### Example 3: Invalid Property Access **Error**: ```json { "type": "invalid_expression", "property": "text", "message": "Cannot access property 'user' of undefined", "current": "={{$json.data.user.name}}" } ``` **Broken Configuration**: ```javascript { "text": "={{$json.data.user.name}}" // ❌ Structure doesn't exist } ``` **Fix** (with safe navigation): ```javascript { "text": "={{$json.data?.user?.name || 'Unknown'}}" // ✅ Safe navigation + fallback } ``` #### Example 4: Webhook Data Access Error **Error**: ```json { "type": "invalid_expression", "property": "value", "message": "Property 'email' not found in $json", "current": "={{$json.email}}" } ``` **Common Gotcha**: Webhook data is under `.body`! **Broken Configuration**: ```javascript { "field": "email", "value": "={{$json.email}}" // ❌ Missing .body } ``` **Fix**: ```javascript { "field": "email", "value": "={{$json.body.email}}" // ✅ Webhook data under .body } ``` --- ### 5. invalid_reference **What it means**: Configuration references a node that doesn't exist in the workflow **When it occurs**: - Node was renamed or deleted - Typo in node name - Copy-pasting from another workflow **Less common error** > **Which of these validation actually catches**: a broken *connection* to a missing node (Example 2) is a hard error under every profile — `Connection to non-existent node: "X" from "Y"`. A node reference *inside an expression* (Examples 1 & 3, e.g. `$('Old Name')`) is **not** statically resolved — it fails at execution, not during validation. Fix expression references by hand or with the n8n Expression Syntax skill; fix connection references with `cleanStaleConnections`. #### Example 1: Deleted Node Reference **Error**: ```json { "type": "invalid_reference", "property": "expression", "message": "Node 'Transform Data' does not exist in workflow", "referenced_node": "Transform Data" } ``` **Broken Configuration**: ```javascript { "value": "={{$node['Transform Data'].json.result}}" // ❌ Node deleted } ``` **Fix**: ```javascript // Option 1: Update to existing node { "value": "={{$node['Set'].json.result}}" } // Option 2: Remove expression if not needed { "value": "default_value" } ``` #### Example 2: Connection to Non-Existent Node **Error**: ```json { "type": "invalid_reference", "message": "Connection references node 'Slack1' which does not exist", "source": "HTTP Request", "target": "Slack1" } ``` **Fix**: Use `cleanStaleConnections` operation: ```javascript n8n_update_partial_workflow({ id: "workflow-id", operations: [{ type: "cleanStaleConnections" }] }) ``` #### Example 3: Renamed Node Not Updated **Error**: ```json { "type": "invalid_reference", "property": "expression", "message": "Node 'Get Weather' does not exist (did you mean 'Weather API'?)", "referenced_node": "Get Weather", "suggestions": ["Weather API"] } ``` **Broken Configuration**: ```javascript { "value": "={{$node['Get Weather'].json.temperature}}" // ❌ Old name } ``` **Fix**: ```javascript { "value": "={{$node['Weather API'].json.temperature}}" // ✅ Current name } ``` --- ## Warnings (Should Fix) ### 6. best_practice **What it means**: Configuration works but doesn't follow best practices **Severity**: Warning (doesn't block execution) — surfaces under `ai-friendly` / `strict` only (n8n-mcp ≥ 2.63.0). Error-handling *style* is never a hard error. **When acceptable**: Development, testing, simple workflows **When to fix**: Production workflows, critical operations #### Example 1: Missing Error Handling **Warning**: ```json { "type": "best_practice", "property": "onError", "message": "Slack API can have rate limits and connection issues", "suggestion": "Add error handling: onError: 'continueRegularOutput'" } ``` **Current Configuration**: ```javascript { "resource": "message", "operation": "post", "channel": "#alerts" // No error handling ⚠️ } ``` **Recommended Fix** (modern `onError`, set at node level): ```javascript { "onError": "continueRegularOutput", // prefer this over deprecated continueOnFail "retryOnFail": true, // maxTries defaults to 3 — stating it isn't required "parameters": { "resource": "message", "operation": "post", "channel": "#alerts" } } ``` #### Example 2: No Retry Logic **Warning**: ```json { "type": "best_practice", "property": "retryOnFail", "message": "External API calls should retry on failure", "suggestion": "Add retryOnFail: true, maxTries: 3, waitBetweenTries: 1000" } ``` **When to ignore**: Idempotent operations, APIs with their own retry logic **When to fix**: Flaky external services, production automation --- ### 7. deprecated **What it means**: Using a genuinely deprecated feature (e.g. `continueOnFail: true` — the validator suggests `onError: 'continueRegularOutput'` instead) **Severity**: Warning (still works but may stop working in future) — surfaces under every profile **When to fix**: Always (eventually) #### Example 1: Outdated typeVersion (suggestion, not a deprecation) Running an older-but-supported `typeVersion` is **normal, supported n8n behavior** — the vast majority of production workflows do. It is now a **suggestion** surfaced only under `ai-friendly` / `strict` (n8n-mcp ≥ 2.63.0), not a deprecation warning, and never an error. A `typeVersion` that *never existed* on a core node is still a hard error (it fails activation). **Suggestion** (plain-string, `ai-friendly` / `strict`): ``` Outdated typeVersion for node "Slack": 1. Latest is 2.3. ``` **Fix** (optional — only if you want the newer node behavior): ```javascript { "type": "n8n-nodes-base.slack", "typeVersion": 2.3, // ✅ Updated — may need config changes for the new version } ``` > `n8n_autofix_workflow` offers `typeversion-upgrade` (to latest, with migration) and `typeversion-correction` (downgrade an *unsupported* version to a real one). --- ### 8. performance **What it means**: Configuration may cause performance issues **Severity**: Warning **When to fix**: High-volume workflows, large datasets #### Example 1: Unbounded Query **Warning**: ```json { "type": "performance", "property": "query", "message": "SELECT without LIMIT can return massive datasets", "suggestion": "Add LIMIT clause or use pagination" } ``` **Current**: ```sql SELECT * FROM users WHERE active = true ``` **Fix**: ```sql SELECT * FROM users WHERE active = true LIMIT 1000 ``` --- ## Auto-Sanitization Fixes ### 9. operator_structure **What it means**: The exact shape of an IF/Switch/Filter condition (`singleValue`, `conditions.options` metadata) **Severity**: Not a validation finding (n8n-mcp ≥ 2.63.0) **Auto-Fix**: ✅ Normalized automatically on workflow save Validation **accepts** a condition whether or not `singleValue` and the `conditions.options` sub-fields are present — n8n derives unary-ness from the operator name and defaults the metadata. The sanitizer still tidies these into the canonical form on save, so you never need to hand-write them either way. The before/after below is what the sanitizer produces, **not** something the validator errors on. **Still real errors** (these are *not* auto-fixed — they change behavior): a legacy v1 operator name (e.g. `smaller`) inside a v2 structure (`"Operation 'smaller' is not valid for type 'string'"`), a v1-shaped `conditions` object on a v2 node (silently evaluates true), and a filter object with no conditions at all. #### Normalized on Save: Binary Operators **Before** (you create this): ```javascript { "type": "boolean", "operation": "equals", "singleValue": true // ❌ Wrong for binary operator } ``` **After** (auto-sanitization fixes it): ```javascript { "type": "boolean", "operation": "equals" // singleValue removed ✅ } ``` **You don't need to do anything** - this is fixed on save! #### Normalized on Save: Unary Operators **Before**: ```javascript { "type": "boolean", "operation": "isEmpty" // Missing singleValue ❌ } ``` **After**: ```javascript { "type": "boolean", "operation": "isEmpty", "singleValue": true // ✅ Added automatically } ``` **What you should do**: Trust auto-sanitization, don't manually fix these! --- ## patchNodeField Errors **What it means**: A `patchNodeField` operation failed during `n8n_update_partial_workflow` The `patchNodeField` operation is strict by design — it errors instead of silently continuing when something is wrong. This catches mistakes early but means you need to handle these specific error cases. ### Error: Find string not found The patch's `find` value doesn't exist in the target field. This usually means the content was already changed, or the find string has a typo. ``` patchNodeField: find string not found in field "parameters.jsCode" ``` **How to fix**: Double-check the exact string. Use `n8n_get_workflow` to inspect the current field value. Whitespace and line endings matter — if unsure, use `regex: true` with `\s+` for flexible whitespace matching. ### Error: Ambiguous match (multiple occurrences) The find string appears more than once in the field. Without `replaceAll: true`, this is treated as ambiguous and rejected. ``` patchNodeField: find string matches 3 times in field "parameters.jsCode" — set replaceAll: true to replace all, or use a more specific find string ``` **How to fix**: Either set `replaceAll: true` if you want to replace all occurrences, or make your find string more specific to match only the intended location. ### Error: Invalid regex pattern When `regex: true`, the pattern is validated for correctness and safety. ``` patchNodeField: invalid or unsafe regex pattern ``` **How to fix**: Check regex syntax. Nested quantifiers like `(a+)+` and overlapping alternations like `(\w|\d)+` are rejected as ReDoS risks. Simplify the pattern. --- ## Auto-Sanitization: What It CANNOT Fix Auto-sanitization handles operator structure (binary/unary `singleValue`, IF/Switch metadata) automatically on every save. It does **not** fix these — you must handle them manually: ### Broken Connections References to non-existent nodes. **Solution**: Use the `cleanStaleConnections` operation in `n8n_update_partial_workflow`. ### Branch Count Mismatches 3 Switch rules but only 2 output connections. **Solution**: Add missing connections or remove extra rules. ### Paradoxical Corrupt States API returns corrupt data but rejects updates. **Solution**: May require manual database intervention. --- ## Recovery Patterns ### Pattern 1: Progressive Validation **Problem**: Too many errors at once **Solution**: ```javascript // Step 1: Minimal valid config let config = { resource: "message", operation: "post", channel: "#general", text: "Hello" }; validate_node({nodeType: "nodes-base.slack", config, profile: "runtime"}); // ✅ Valid // Step 2: Add features one by one config.attachments = [...]; validate_node({nodeType: "nodes-base.slack", config, profile: "runtime"}); config.blocks = [...]; validate_node({nodeType: "nodes-base.slack", config, profile: "runtime"}); ``` ### Pattern 2: Error Triage **Problem**: Multiple errors **Solution**: ```javascript const result = validate_node({...}); // 1. Fix errors (must fix) result.errors.forEach(error => { console.log(`MUST FIX: ${error.property} - ${error.message}`); }); // 2. Review warnings (should fix) result.warnings.forEach(warning => { console.log(`SHOULD FIX: ${warning.property} - ${warning.message}`); }); // 3. Consider suggestions (optional) result.suggestions.forEach(sug => { console.log(`OPTIONAL: ${sug.message}`); }); ``` ### Pattern 3: Use get_node **Problem**: Don't know what's required **Solution**: ```javascript // Before configuring, check requirements const info = get_node({ nodeType: "nodes-base.slack" }); // Look for required fields info.properties.forEach(prop => { if (prop.required) { console.log(`Required: ${prop.name} (${prop.type})`); } }); ``` --- ## Summary **Most Common Errors**: 1. `missing_required` (45%) - Always check get_node 2. `invalid_value` (28%) - Check allowed values 3. `type_mismatch` (12%) - Use correct data types 4. `invalid_expression` (8%) - Use Expression Syntax skill 5. `invalid_reference` (5%) - Clean stale connections **Auto-Fixed**: - `operator_structure` - Trust auto-sanitization! **Related Skills**: - **[SKILL.md](SKILL.md)** - Main validation guide - **[FALSE_POSITIVES.md](FALSE_POSITIVES.md)** - When to ignore warnings - **n8n Expression Syntax** - Fix expression errors - **n8n MCP Tools Expert** - Use validation tools correctly