Add n8n workflow specialist skill
Comprehensive skill for n8n workflow automation including: - Workflow design and node configuration - Expression writing reference (14 KB) - Comprehensive troubleshooting guide (15 KB) - Examples for common use cases - Performance optimization tips 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
609
skills/n8n-workflow-specialist/TROUBLESHOOTING.md
Normal file
609
skills/n8n-workflow-specialist/TROUBLESHOOTING.md
Normal file
@@ -0,0 +1,609 @@
|
||||
# n8n Troubleshooting Guide
|
||||
|
||||
Common issues and solutions for n8n workflow debugging.
|
||||
|
||||
## Table of Contents
|
||||
- [Authentication Errors](#authentication-errors)
|
||||
- [Expression Errors](#expression-errors)
|
||||
- [HTTP Request Errors](#http-request-errors)
|
||||
- [Webhook Issues](#webhook-issues)
|
||||
- [Data Transformation Problems](#data-transformation-problems)
|
||||
- [Performance Issues](#performance-issues)
|
||||
- [Execution Errors](#execution-errors)
|
||||
- [Node-Specific Issues](#node-specific-issues)
|
||||
|
||||
## Authentication Errors
|
||||
|
||||
### 401 Unauthorized
|
||||
|
||||
**Symptoms:**
|
||||
- HTTP Request node returns 401 status code
|
||||
- Error message: "Unauthorized" or "Invalid credentials"
|
||||
|
||||
**Common Causes & Solutions:**
|
||||
|
||||
1. **Incorrect Credentials**
|
||||
- Check that the correct credential is selected in the node
|
||||
- Verify the credential contains the right API key/token
|
||||
- Re-create the credential if suspicious
|
||||
|
||||
2. **Expired Token**
|
||||
- OAuth2 tokens expire - reconnect the credential
|
||||
- API keys may have expiration dates - check provider dashboard
|
||||
- Refresh tokens if using OAuth2
|
||||
|
||||
3. **Wrong Authentication Method**
|
||||
- Verify API requires Bearer token, Basic Auth, or API Key
|
||||
- Check API documentation for correct header format
|
||||
- Common headers:
|
||||
- `Authorization: Bearer TOKEN`
|
||||
- `Authorization: Basic BASE64_CREDENTIALS`
|
||||
- `X-API-Key: YOUR_KEY`
|
||||
|
||||
4. **Missing Headers**
|
||||
```javascript
|
||||
// Common required headers
|
||||
{
|
||||
"Authorization": "Bearer YOUR_TOKEN",
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "n8n-workflow"
|
||||
}
|
||||
```
|
||||
|
||||
5. **Incorrect Scope/Permissions**
|
||||
- OAuth2 credential may lack required scopes
|
||||
- API key may not have permission for the endpoint
|
||||
- Check provider's permission settings
|
||||
|
||||
**Debugging Steps:**
|
||||
```bash
|
||||
# Test authentication manually with curl
|
||||
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
https://api.example.com/endpoint
|
||||
|
||||
# Check if token is valid
|
||||
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
||||
https://api.example.com/me
|
||||
```
|
||||
|
||||
### 403 Forbidden
|
||||
|
||||
**Symptoms:**
|
||||
- HTTP Request returns 403 status code
|
||||
- "Access Denied" or "Forbidden" error
|
||||
|
||||
**Solutions:**
|
||||
1. **Insufficient Permissions**
|
||||
- API key/token lacks permission for the resource
|
||||
- Check if account has access to the endpoint
|
||||
- Verify subscription/plan level
|
||||
|
||||
2. **IP Whitelist**
|
||||
- Some APIs require IP whitelisting
|
||||
- Add n8n server IP to allowed list
|
||||
- Check firewall rules
|
||||
|
||||
3. **Rate Limiting**
|
||||
- Too many requests in short time
|
||||
- Implement delays between requests
|
||||
- Use Split In Batches node with batch size limit
|
||||
|
||||
## Expression Errors
|
||||
|
||||
### "Cannot read property 'X' of undefined"
|
||||
|
||||
**Cause:** Trying to access a property that doesn't exist
|
||||
|
||||
**Solutions:**
|
||||
```javascript
|
||||
// Bad: Will fail if user is undefined
|
||||
{{ $json.user.email }}
|
||||
|
||||
// Good: Use optional chaining
|
||||
{{ $json.user?.email }}
|
||||
|
||||
// Good: Provide default value
|
||||
{{ $json.user?.email ?? 'no-email@example.com' }}
|
||||
|
||||
// Good: Check existence first
|
||||
{{ $json.user && $json.user.email ? $json.user.email : 'N/A' }}
|
||||
```
|
||||
|
||||
### "Node not found"
|
||||
|
||||
**Cause:** Referenced node name doesn't match exactly
|
||||
|
||||
**Solutions:**
|
||||
```javascript
|
||||
// Bad: Wrong node name
|
||||
{{ $node["Http Request"].json }}
|
||||
|
||||
// Good: Exact match (case-sensitive)
|
||||
{{ $node["HTTP Request"].json }}
|
||||
|
||||
// Best: Use debug panel to verify exact node name
|
||||
```
|
||||
|
||||
**Debugging:**
|
||||
1. Check node name exactly as it appears in workflow
|
||||
2. Node names are case-sensitive
|
||||
3. Spaces and special characters must match exactly
|
||||
4. Renamed nodes? Update all expressions
|
||||
|
||||
### Expression Syntax Errors
|
||||
|
||||
**Common Mistakes:**
|
||||
```javascript
|
||||
// Bad: Missing quotes around property names with dashes
|
||||
{{ $json.user-name }}
|
||||
|
||||
// Good: Use bracket notation
|
||||
{{ $json["user-name"] }}
|
||||
|
||||
// Bad: Trying to use expressions in Code node
|
||||
const value = {{ $json.value }}; // Won't work!
|
||||
|
||||
// Good: In Code node, access directly
|
||||
const value = items[0].json.value;
|
||||
|
||||
// Bad: Wrong quotation marks in expression
|
||||
{{ $json.text === "value" }}
|
||||
|
||||
// Good: Use single quotes in expressions
|
||||
{{ $json.text === 'value' }}
|
||||
```
|
||||
|
||||
### DateTime Errors
|
||||
|
||||
**"Invalid DateTime"**
|
||||
```javascript
|
||||
// Bad: Invalid date format
|
||||
{{ DateTime.fromISO($json.badDate) }}
|
||||
|
||||
// Good: Validate before parsing
|
||||
{{ $json.date ? DateTime.fromISO($json.date).toISO() : '' }}
|
||||
|
||||
// Good: Handle invalid dates
|
||||
{{ DateTime.fromISO($json.date).isValid ?
|
||||
DateTime.fromISO($json.date).toFormat('yyyy-MM-dd') :
|
||||
'Invalid Date' }}
|
||||
```
|
||||
|
||||
## HTTP Request Errors
|
||||
|
||||
### 404 Not Found
|
||||
|
||||
**Solutions:**
|
||||
1. **Verify URL**
|
||||
```javascript
|
||||
// Check dynamic URLs evaluate correctly
|
||||
{{ `https://api.example.com/users/${$json.userId}` }}
|
||||
|
||||
// Debug: Use Set node to see final URL
|
||||
// Set field "debug_url" to your URL expression
|
||||
```
|
||||
|
||||
2. **Check API Endpoint**
|
||||
- Endpoint may have changed (check API docs)
|
||||
- Verify API version in URL
|
||||
- Check for typos in path
|
||||
|
||||
3. **Resource Doesn't Exist**
|
||||
- ID might be invalid
|
||||
- Resource might have been deleted
|
||||
- Test with known valid ID
|
||||
|
||||
### Timeout Errors
|
||||
|
||||
**"Request timed out"**
|
||||
|
||||
**Solutions:**
|
||||
1. **Increase Timeout**
|
||||
- Go to node settings
|
||||
- Increase "Timeout" value (default: 300000ms = 5 minutes)
|
||||
- For slow APIs, increase to 600000ms (10 minutes)
|
||||
|
||||
2. **Optimize Request**
|
||||
- Add pagination for large datasets
|
||||
- Request only needed fields
|
||||
- Use filtering on API side
|
||||
- Consider caching responses
|
||||
|
||||
3. **Check API Health**
|
||||
- API might be down or slow
|
||||
- Test endpoint in browser/Postman
|
||||
- Check API status page
|
||||
|
||||
### SSL/TLS Errors
|
||||
|
||||
**"unable to verify the first certificate"**
|
||||
|
||||
**Solutions:**
|
||||
1. **Ignore SSL Issues** (development only!)
|
||||
- In HTTP Request node settings
|
||||
- Enable "Ignore SSL Issues"
|
||||
- ⚠️ Not recommended for production
|
||||
|
||||
2. **Update Certificates**
|
||||
- Update system certificates
|
||||
- Contact API provider about SSL issues
|
||||
|
||||
### CORS Errors
|
||||
|
||||
**Note:** n8n workflows run server-side, so CORS shouldn't be an issue. If you see CORS errors:
|
||||
- You might be testing in browser (test in n8n instead)
|
||||
- The error might be from a different issue
|
||||
- Check actual error message in execution logs
|
||||
|
||||
## Webhook Issues
|
||||
|
||||
### "Webhook waiting for response"
|
||||
|
||||
**Cause:** Webhook is in "Respond to Webhook" mode but no response sent
|
||||
|
||||
**Solution:**
|
||||
```
|
||||
Webhook Node (Wait for Webhook Call)
|
||||
→ Process Data
|
||||
→ Respond to Webhook Node (REQUIRED)
|
||||
```
|
||||
|
||||
**Always add "Respond to Webhook" node when using "Wait for Webhook Call"**
|
||||
|
||||
### Webhook Not Triggering
|
||||
|
||||
**Debugging Steps:**
|
||||
1. **Verify Workflow is Active**
|
||||
- Workflow must be activated (not just saved)
|
||||
- Check toggle switch in top-right is ON
|
||||
|
||||
2. **Check Webhook URL**
|
||||
- Copy exact URL from Webhook node
|
||||
- Verify no typos when configuring external service
|
||||
- Test with curl:
|
||||
```bash
|
||||
curl -X POST https://your-n8n.com/webhook/your-path \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"test": "data"}'
|
||||
```
|
||||
|
||||
3. **Verify HTTP Method**
|
||||
- Webhook expects POST but receiving GET (or vice versa)
|
||||
- Match method in Webhook node config
|
||||
|
||||
4. **Check Authentication**
|
||||
- If "Webhook Authentication" is set, include credentials
|
||||
- Verify Header Auth name and value match
|
||||
|
||||
5. **Firewall/Network Issues**
|
||||
- n8n instance must be accessible from internet
|
||||
- Check firewall rules
|
||||
- Verify DNS is resolving correctly
|
||||
|
||||
### Webhook Returns Error to Caller
|
||||
|
||||
**Customize response:**
|
||||
```
|
||||
Webhook → IF Node
|
||||
→ Success Path → Respond (200 OK)
|
||||
→ Error Path → Respond to Webhook (400/500 with error message)
|
||||
```
|
||||
|
||||
Use "Respond to Webhook" node to control:
|
||||
- Status code
|
||||
- Headers
|
||||
- Response body
|
||||
- Response format (JSON, text, etc.)
|
||||
|
||||
## Data Transformation Problems
|
||||
|
||||
### Empty Results After Transformation
|
||||
|
||||
**Cause:** Filter or map returns empty array
|
||||
|
||||
**Debugging:**
|
||||
```javascript
|
||||
// Check what data looks like before transformation
|
||||
// Add a Set node to inspect: {{ $json }}
|
||||
|
||||
// Ensure filter condition is correct
|
||||
{{ $json.items.filter(item => item.status === 'active') }}
|
||||
|
||||
// Check if property exists
|
||||
{{ $json.items.filter(item => item.status && item.status === 'active') }}
|
||||
|
||||
// Verify array is actually an array
|
||||
{{ Array.isArray($json.items) ? $json.items.length : 0 }}
|
||||
```
|
||||
|
||||
### Data Type Mismatches
|
||||
|
||||
**String vs Number Issues:**
|
||||
```javascript
|
||||
// Problem: Comparing string with number
|
||||
{{ $json.age > 18 }} // Fails if age is "25" (string)
|
||||
|
||||
// Solution: Parse to number
|
||||
{{ parseInt($json.age) > 18 }}
|
||||
{{ parseFloat($json.price) > 99.99 }}
|
||||
|
||||
// Problem: Math on strings
|
||||
{{ $json.price * 1.2 }} // Fails if price is "$99.99"
|
||||
|
||||
// Solution: Clean and parse
|
||||
{{ parseFloat($json.price.replace('$', '')) * 1.2 }}
|
||||
```
|
||||
|
||||
### JSON Parse Errors
|
||||
|
||||
**"Unexpected token in JSON"**
|
||||
|
||||
**Solutions:**
|
||||
```javascript
|
||||
// Problem: Invalid JSON string
|
||||
JSON.parse($json.data)
|
||||
|
||||
// Solution: Validate first (in Code node)
|
||||
try {
|
||||
const data = JSON.parse(items[0].json.rawData);
|
||||
return [{ json: data }];
|
||||
} catch (error) {
|
||||
return [{ json: {
|
||||
error: 'Invalid JSON',
|
||||
raw: items[0].json.rawData
|
||||
}}];
|
||||
}
|
||||
|
||||
// Solution: Check if already an object
|
||||
if (typeof $json.data === 'string') {
|
||||
JSON.parse($json.data)
|
||||
} else {
|
||||
$json.data
|
||||
}
|
||||
```
|
||||
|
||||
## Performance Issues
|
||||
|
||||
### Workflow Execution Too Slow
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. **Reduce HTTP Requests**
|
||||
```
|
||||
// Bad: Loop making individual requests
|
||||
Loop → HTTP Request (100x)
|
||||
|
||||
// Good: Batch request
|
||||
Batch Items → HTTP Request with array
|
||||
```
|
||||
|
||||
2. **Use Split In Batches**
|
||||
```
|
||||
Split In Batches (batch size: 10)
|
||||
→ Process Batch
|
||||
→ Loop Back
|
||||
```
|
||||
|
||||
3. **Optimize Expressions**
|
||||
```javascript
|
||||
// Bad: Complex expression repeated
|
||||
{{ $json.items.filter(...).map(...).reduce(...) }}
|
||||
|
||||
// Good: Use Code node for complex logic
|
||||
const result = items[0].json.items
|
||||
.filter(item => item.active)
|
||||
.map(item => item.value)
|
||||
.reduce((sum, val) => sum + val, 0);
|
||||
return [{ json: { total: result } }];
|
||||
```
|
||||
|
||||
4. **Cache Frequently Accessed Data**
|
||||
- Store results in Set node
|
||||
- Reuse instead of re-fetching
|
||||
- Consider using database for persistent cache
|
||||
|
||||
### Memory Errors
|
||||
|
||||
**"JavaScript heap out of memory"**
|
||||
|
||||
**Solutions:**
|
||||
1. **Process in Batches**
|
||||
- Don't load all data at once
|
||||
- Use Split In Batches node
|
||||
- Process incrementally
|
||||
|
||||
2. **Reduce Item Count**
|
||||
- Add Limit node after triggers
|
||||
- Use pagination in API requests
|
||||
- Filter data at source
|
||||
|
||||
3. **Optimize Data Size**
|
||||
- Remove unnecessary fields with Set node
|
||||
- Don't store large binary data in JSON
|
||||
- Use binary data type for files
|
||||
|
||||
## Execution Errors
|
||||
|
||||
### "Workflow did not finish"
|
||||
|
||||
**Causes:**
|
||||
1. **Infinite Loop**
|
||||
- Missing stop condition in loop
|
||||
- Always include maximum iterations
|
||||
|
||||
2. **Timeout**
|
||||
- Workflow taking too long
|
||||
- Default timeout might be exceeded
|
||||
- Optimize or increase timeout settings
|
||||
|
||||
### "Missing node parameter"
|
||||
|
||||
**Cause:** Required field is empty or expression evaluates to empty
|
||||
|
||||
**Solutions:**
|
||||
```javascript
|
||||
// Provide default values
|
||||
{{ $json.email || 'noreply@example.com' }}
|
||||
|
||||
// Validate before using
|
||||
{{ $json.userId ? $json.userId : 'default-id' }}
|
||||
|
||||
// Use IF node to branch based on data availability
|
||||
IF node: {{ $json.email !== undefined && $json.email !== '' }}
|
||||
→ True: Continue with email
|
||||
→ False: Skip or use default
|
||||
```
|
||||
|
||||
### Workflow Executes Multiple Times
|
||||
|
||||
**Causes:**
|
||||
1. **Trigger Firing Multiple Times**
|
||||
- Webhook called multiple times by external service
|
||||
- Schedule trigger overlapping with long execution
|
||||
- Email trigger processing same email multiple times
|
||||
|
||||
**Solutions:**
|
||||
- Add deduplication logic
|
||||
- Use IF node to check if already processed
|
||||
- Store processed IDs in database
|
||||
- Adjust trigger settings (e.g., mark emails as read)
|
||||
|
||||
## Node-Specific Issues
|
||||
|
||||
### Code Node Issues
|
||||
|
||||
**"items is not defined"**
|
||||
```javascript
|
||||
// Wrong: Using old syntax
|
||||
for (item of items) { }
|
||||
|
||||
// Correct: Access items array
|
||||
for (const item of items) { }
|
||||
|
||||
// Or use functional approach
|
||||
return items.map(item => ({
|
||||
json: {
|
||||
// transformed data
|
||||
}
|
||||
}));
|
||||
```
|
||||
|
||||
**"Must return array"**
|
||||
```javascript
|
||||
// Wrong: Returning object
|
||||
return { json: { value: 123 } };
|
||||
|
||||
// Correct: Return array of items
|
||||
return [{ json: { value: 123 } }];
|
||||
|
||||
// Multiple items
|
||||
return [
|
||||
{ json: { id: 1 } },
|
||||
{ json: { id: 2 } }
|
||||
];
|
||||
```
|
||||
|
||||
### Set Node Issues
|
||||
|
||||
**"Expression error in field"**
|
||||
- Check expression syntax
|
||||
- Verify referenced node names
|
||||
- Test expression in expression editor
|
||||
- Use debug panel to see available data
|
||||
|
||||
### IF Node Issues
|
||||
|
||||
**"All items ending up in one branch"**
|
||||
- Verify condition logic
|
||||
- Check data types (string vs number)
|
||||
- Use debug panel to see actual values
|
||||
- Test condition in expression editor
|
||||
|
||||
### Split In Batches Issues
|
||||
|
||||
**"Loop not completing"**
|
||||
- Ensure "Loop Over Items" is connected back to Split In Batches
|
||||
- Verify batch size is appropriate
|
||||
- Check for errors in loop that stop execution
|
||||
|
||||
## General Debugging Tips
|
||||
|
||||
1. **Use Debug Panel**
|
||||
- Click on node to see input/output
|
||||
- Inspect data structure before writing expressions
|
||||
- Check for null/undefined values
|
||||
|
||||
2. **Test Incrementally**
|
||||
- Build workflow step by step
|
||||
- Test each node before adding next
|
||||
- Use "Execute Node" to test individual nodes
|
||||
|
||||
3. **Add Logging**
|
||||
```javascript
|
||||
// In Code node
|
||||
console.log('Debug info:', items[0].json);
|
||||
// View in execution logs
|
||||
```
|
||||
|
||||
4. **Use Set Nodes for Debugging**
|
||||
```javascript
|
||||
// Add Set node with debug fields
|
||||
debug_field: {{ $json }}
|
||||
debug_type: {{ typeof $json.value }}
|
||||
debug_length: {{ $json.items?.length }}
|
||||
```
|
||||
|
||||
5. **Check Execution Logs**
|
||||
- View past executions
|
||||
- Look for error messages
|
||||
- Compare successful vs failed runs
|
||||
|
||||
6. **Simplify**
|
||||
- Remove complex expressions temporarily
|
||||
- Use static values to isolate issues
|
||||
- Test with minimal data first
|
||||
|
||||
7. **Read Error Messages Carefully**
|
||||
- Error often points to exact issue
|
||||
- Note line numbers in Code nodes
|
||||
- Google specific error messages
|
||||
|
||||
## Getting Help
|
||||
|
||||
If you're still stuck:
|
||||
|
||||
1. **Check n8n Documentation**
|
||||
- https://docs.n8n.io/
|
||||
- Node-specific docs
|
||||
- Expression reference
|
||||
|
||||
2. **Community Forum**
|
||||
- https://community.n8n.io/
|
||||
- Search for similar issues
|
||||
- Post workflow JSON for help
|
||||
|
||||
3. **GitHub Issues**
|
||||
- https://github.com/n8n-io/n8n
|
||||
- Report bugs
|
||||
- Check known issues
|
||||
|
||||
4. **Export Workflow**
|
||||
- Download as JSON for sharing
|
||||
- Remove sensitive credentials
|
||||
- Include error messages when asking for help
|
||||
|
||||
## Quick Reference: Common Error Messages
|
||||
|
||||
| Error | Common Cause | Solution |
|
||||
|-------|-------------|----------|
|
||||
| 401 Unauthorized | Wrong credentials | Check credential, verify API key |
|
||||
| 403 Forbidden | Insufficient permissions | Check API permissions, IP whitelist |
|
||||
| 404 Not Found | Wrong URL/endpoint | Verify URL, check API docs |
|
||||
| 500 Internal Server Error | API issue or bad request | Check request body, verify API status |
|
||||
| Timeout | Request too slow | Increase timeout, optimize request |
|
||||
| Expression error | Syntax or missing data | Check syntax, verify node names |
|
||||
| Cannot read property | Undefined value | Use optional chaining `?.` |
|
||||
| Node not found | Wrong node name | Match exact node name (case-sensitive) |
|
||||
| Invalid DateTime | Bad date format | Validate date before parsing |
|
||||
| JavaScript heap out of memory | Too much data | Process in batches, reduce data size |
|
||||
Reference in New Issue
Block a user