skills n8n: garde 5 actives, désactive 3 (config Qwen3.6 local)

This commit is contained in:
Tallagrand Thierry
2026-07-17 00:47:42 +02:00
parent 93aa43d0d0
commit 7a9e56f17c
40 changed files with 22291 additions and 1 deletions

View File

@@ -0,0 +1,764 @@
# Built-in Functions - JavaScript Code Node
Complete reference for n8n's built-in JavaScript functions and helpers.
---
## Overview
n8n Code nodes provide powerful built-in functions beyond standard JavaScript. This guide covers:
1. **$helpers.httpRequest()** - Make HTTP requests
2. **DateTime (Luxon)** - Advanced date/time operations
3. **$jmespath()** - Query JSON structures
4. **$getWorkflowStaticData()** - Persistent storage
5. **Standard JavaScript Globals** - Math, JSON, console, etc.
6. **Available Node.js Modules** - crypto, Buffer, URL
---
## 1. $helpers.httpRequest() - HTTP Requests
Make HTTP requests directly from Code nodes without using HTTP Request node.
### Basic Usage
```javascript
const response = await $helpers.httpRequest({
method: 'GET',
url: 'https://api.example.com/users'
});
return [{json: {data: response}}];
```
### Complete Options
```javascript
const response = await $helpers.httpRequest({
method: 'POST', // GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS
url: 'https://api.example.com/users',
headers: {
'Authorization': 'Bearer token123',
'Content-Type': 'application/json',
'User-Agent': 'n8n-workflow'
},
body: {
name: 'John Doe',
email: 'john@example.com'
},
qs: { // Query string parameters
page: 1,
limit: 10
},
timeout: 10000, // Milliseconds (default: no timeout)
json: true, // Auto-parse JSON response (default: true)
simple: false, // Don't throw on HTTP errors (default: true)
resolveWithFullResponse: false // Return only body (default: false)
});
```
### GET Request
```javascript
// Simple GET
const users = await $helpers.httpRequest({
method: 'GET',
url: 'https://api.example.com/users'
});
return [{json: {users}}];
```
```javascript
// GET with query parameters
const results = await $helpers.httpRequest({
method: 'GET',
url: 'https://api.example.com/search',
qs: {
q: 'javascript',
page: 1,
per_page: 50
}
});
return [{json: results}];
```
### POST Request
```javascript
// POST with JSON body
const newUser = await $helpers.httpRequest({
method: 'POST',
url: 'https://api.example.com/users',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + $env.API_KEY
},
body: {
name: $json.body.name,
email: $json.body.email,
role: 'user'
}
});
return [{json: newUser}];
```
### PUT/PATCH Request
```javascript
// Update resource
const updated = await $helpers.httpRequest({
method: 'PATCH',
url: `https://api.example.com/users/${userId}`,
body: {
name: 'Updated Name',
status: 'active'
}
});
return [{json: updated}];
```
### DELETE Request
```javascript
// Delete resource
await $helpers.httpRequest({
method: 'DELETE',
url: `https://api.example.com/users/${userId}`,
headers: {
'Authorization': 'Bearer ' + $env.API_KEY
}
});
return [{json: {deleted: true, userId}}];
```
### Authentication Patterns
```javascript
// Bearer Token
const response = await $helpers.httpRequest({
url: 'https://api.example.com/data',
headers: {
'Authorization': `Bearer ${$env.API_TOKEN}`
}
});
```
```javascript
// API Key in Header
const response = await $helpers.httpRequest({
url: 'https://api.example.com/data',
headers: {
'X-API-Key': $env.API_KEY
}
});
```
```javascript
// Basic Auth (manual)
const credentials = Buffer.from(`${username}:${password}`).toString('base64');
const response = await $helpers.httpRequest({
url: 'https://api.example.com/data',
headers: {
'Authorization': `Basic ${credentials}`
}
});
```
### Error Handling
```javascript
// Handle HTTP errors gracefully
try {
const response = await $helpers.httpRequest({
method: 'GET',
url: 'https://api.example.com/users',
simple: false // Don't throw on 4xx/5xx
});
if (response.statusCode >= 200 && response.statusCode < 300) {
return [{json: {success: true, data: response.body}}];
} else {
return [{
json: {
success: false,
status: response.statusCode,
error: response.body
}
}];
}
} catch (error) {
return [{
json: {
success: false,
error: error.message
}
}];
}
```
### Full Response Access
```javascript
// Get full response including headers and status
const response = await $helpers.httpRequest({
url: 'https://api.example.com/data',
resolveWithFullResponse: true
});
return [{
json: {
statusCode: response.statusCode,
headers: response.headers,
body: response.body,
rateLimit: response.headers['x-ratelimit-remaining']
}
}];
```
---
## 2. DateTime (Luxon) - Date & Time Operations
n8n includes Luxon for powerful date/time handling. Access via `DateTime` global.
### Current Date/Time
```javascript
// Current time
const now = DateTime.now();
// Current time in specific timezone
const nowTokyo = DateTime.now().setZone('Asia/Tokyo');
// Today at midnight
const today = DateTime.now().startOf('day');
return [{
json: {
iso: now.toISO(), // "2025-01-20T15:30:00.000Z"
formatted: now.toFormat('yyyy-MM-dd HH:mm:ss'), // "2025-01-20 15:30:00"
unix: now.toSeconds(), // Unix timestamp
millis: now.toMillis() // Milliseconds since epoch
}
}];
```
### Formatting Dates
```javascript
const now = DateTime.now();
return [{
json: {
isoFormat: now.toISO(), // ISO 8601: "2025-01-20T15:30:00.000Z"
sqlFormat: now.toSQL(), // SQL: "2025-01-20 15:30:00.000"
httpFormat: now.toHTTP(), // HTTP: "Mon, 20 Jan 2025 15:30:00 GMT"
// Custom formats
dateOnly: now.toFormat('yyyy-MM-dd'), // "2025-01-20"
timeOnly: now.toFormat('HH:mm:ss'), // "15:30:00"
readable: now.toFormat('MMMM dd, yyyy'), // "January 20, 2025"
compact: now.toFormat('yyyyMMdd'), // "20250120"
withDay: now.toFormat('EEEE, MMMM dd, yyyy'), // "Monday, January 20, 2025"
custom: now.toFormat('dd/MM/yy HH:mm') // "20/01/25 15:30"
}
}];
```
### Parsing Dates
```javascript
// From ISO string
const dt1 = DateTime.fromISO('2025-01-20T15:30:00');
// From specific format
const dt2 = DateTime.fromFormat('01/20/2025', 'MM/dd/yyyy');
// From SQL
const dt3 = DateTime.fromSQL('2025-01-20 15:30:00');
// From Unix timestamp
const dt4 = DateTime.fromSeconds(1737384600);
// From milliseconds
const dt5 = DateTime.fromMillis(1737384600000);
return [{json: {parsed: dt1.toISO()}}];
```
### Date Arithmetic
```javascript
const now = DateTime.now();
return [{
json: {
// Adding time
tomorrow: now.plus({days: 1}).toISO(),
nextWeek: now.plus({weeks: 1}).toISO(),
nextMonth: now.plus({months: 1}).toISO(),
inTwoHours: now.plus({hours: 2}).toISO(),
// Subtracting time
yesterday: now.minus({days: 1}).toISO(),
lastWeek: now.minus({weeks: 1}).toISO(),
lastMonth: now.minus({months: 1}).toISO(),
twoHoursAgo: now.minus({hours: 2}).toISO(),
// Complex operations
in90Days: now.plus({days: 90}).toFormat('yyyy-MM-dd'),
in6Months: now.plus({months: 6}).toFormat('yyyy-MM-dd')
}
}];
```
### Time Comparisons
```javascript
const now = DateTime.now();
const targetDate = DateTime.fromISO('2025-12-31');
return [{
json: {
// Comparisons
isFuture: targetDate > now,
isPast: targetDate < now,
isEqual: targetDate.equals(now),
// Differences
daysUntil: targetDate.diff(now, 'days').days,
hoursUntil: targetDate.diff(now, 'hours').hours,
monthsUntil: targetDate.diff(now, 'months').months,
// Detailed difference
detailedDiff: targetDate.diff(now, ['months', 'days', 'hours']).toObject()
}
}];
```
### Timezone Operations
```javascript
const now = DateTime.now();
return [{
json: {
// Current timezone
local: now.toISO(),
// Convert to different timezone
tokyo: now.setZone('Asia/Tokyo').toISO(),
newYork: now.setZone('America/New_York').toISO(),
london: now.setZone('Europe/London').toISO(),
utc: now.toUTC().toISO(),
// Get timezone info
timezone: now.zoneName, // "America/Los_Angeles"
offset: now.offset, // Offset in minutes
offsetFormatted: now.toFormat('ZZ') // "+08:00"
}
}];
```
### Start/End of Period
```javascript
const now = DateTime.now();
return [{
json: {
startOfDay: now.startOf('day').toISO(),
endOfDay: now.endOf('day').toISO(),
startOfWeek: now.startOf('week').toISO(),
endOfWeek: now.endOf('week').toISO(),
startOfMonth: now.startOf('month').toISO(),
endOfMonth: now.endOf('month').toISO(),
startOfYear: now.startOf('year').toISO(),
endOfYear: now.endOf('year').toISO()
}
}];
```
### Weekday & Month Info
```javascript
const now = DateTime.now();
return [{
json: {
// Day info
weekday: now.weekday, // 1 = Monday, 7 = Sunday
weekdayShort: now.weekdayShort, // "Mon"
weekdayLong: now.weekdayLong, // "Monday"
isWeekend: now.weekday > 5, // Saturday or Sunday
// Month info
month: now.month, // 1-12
monthShort: now.monthShort, // "Jan"
monthLong: now.monthLong, // "January"
// Year info
year: now.year, // 2025
quarter: now.quarter, // 1-4
daysInMonth: now.daysInMonth // 28-31
}
}];
```
---
## 3. $jmespath() - JSON Querying
Query and transform JSON structures using JMESPath syntax.
### Basic Queries
```javascript
const data = $input.first().json;
// Extract specific field
const names = $jmespath(data, 'users[*].name');
// Filter array
const adults = $jmespath(data, 'users[?age >= `18`]');
// Get specific index
const firstUser = $jmespath(data, 'users[0]');
return [{json: {names, adults, firstUser}}];
```
### Advanced Queries
```javascript
const data = $input.first().json;
// Sort and slice
const top5 = $jmespath(data, 'users | sort_by(@, &score) | reverse(@) | [0:5]');
// Extract nested fields
const emails = $jmespath(data, 'users[*].contact.email');
// Multi-field extraction
const simplified = $jmespath(data, 'users[*].{name: name, email: contact.email}');
// Conditional filtering
const premium = $jmespath(data, 'users[?subscription.tier == `premium`]');
return [{json: {top5, emails, simplified, premium}}];
```
### Common Patterns
```javascript
// Pattern 1: Filter and project
const query1 = $jmespath(data, 'products[?price > `100`].{name: name, price: price}');
// Pattern 2: Aggregate functions
const query2 = $jmespath(data, 'sum(products[*].price)');
const query3 = $jmespath(data, 'max(products[*].price)');
const query4 = $jmespath(data, 'length(products)');
// Pattern 3: Nested filtering
const query5 = $jmespath(data, 'categories[*].products[?inStock == `true`]');
return [{json: {query1, query2, query3, query4, query5}}];
```
---
## 4. $getWorkflowStaticData() - Persistent Storage
Store data that persists across workflow executions.
### Basic Usage
```javascript
// Get static data storage
const staticData = $getWorkflowStaticData();
// Initialize counter if doesn't exist
if (!staticData.counter) {
staticData.counter = 0;
}
// Increment counter
staticData.counter++;
return [{
json: {
executionCount: staticData.counter
}
}];
```
### Use Cases
```javascript
// Use Case 1: Rate limiting
const staticData = $getWorkflowStaticData();
const now = Date.now();
if (!staticData.lastRun) {
staticData.lastRun = now;
staticData.runCount = 1;
} else {
const timeSinceLastRun = now - staticData.lastRun;
if (timeSinceLastRun < 60000) { // Less than 1 minute
return [{json: {error: 'Rate limit: wait 1 minute between runs'}}];
}
staticData.lastRun = now;
staticData.runCount++;
}
return [{json: {allowed: true, totalRuns: staticData.runCount}}];
```
```javascript
// Use Case 2: Tracking last processed ID
const staticData = $getWorkflowStaticData();
const currentItems = $input.all();
// Get last processed ID
const lastId = staticData.lastProcessedId || 0;
// Filter only new items
const newItems = currentItems.filter(item => item.json.id > lastId);
// Update last processed ID
if (newItems.length > 0) {
staticData.lastProcessedId = Math.max(...newItems.map(item => item.json.id));
}
return newItems;
```
```javascript
// Use Case 3: Accumulating results
const staticData = $getWorkflowStaticData();
if (!staticData.accumulated) {
staticData.accumulated = [];
}
// Add current items to accumulated list
const currentData = $input.all().map(item => item.json);
staticData.accumulated.push(...currentData);
return [{
json: {
currentBatch: currentData.length,
totalAccumulated: staticData.accumulated.length,
allData: staticData.accumulated
}
}];
```
---
## 5. Standard JavaScript Globals
### Math Object
```javascript
return [{
json: {
// Rounding
rounded: Math.round(3.7), // 4
floor: Math.floor(3.7), // 3
ceil: Math.ceil(3.2), // 4
// Min/Max
max: Math.max(1, 5, 3, 9, 2), // 9
min: Math.min(1, 5, 3, 9, 2), // 1
// Random
random: Math.random(), // 0-1
randomInt: Math.floor(Math.random() * 100), // 0-99
// Other
abs: Math.abs(-5), // 5
sqrt: Math.sqrt(16), // 4
pow: Math.pow(2, 3) // 8
}
}];
```
### JSON Object
```javascript
// Parse JSON string
const jsonString = '{"name": "John", "age": 30}';
const parsed = JSON.parse(jsonString);
// Stringify object
const obj = {name: "John", age: 30};
const stringified = JSON.stringify(obj);
// Pretty print
const pretty = JSON.stringify(obj, null, 2);
return [{json: {parsed, stringified, pretty}}];
```
### console Object
```javascript
// Debug logging (appears in browser console, press F12)
console.log('Processing items:', $input.all().length);
console.log('First item:', $input.first().json);
// Other console methods
console.error('Error message');
console.warn('Warning message');
console.info('Info message');
// Continues to return data
return [{json: {processed: true}}];
```
### Object Methods
```javascript
const obj = {name: "John", age: 30, city: "NYC"};
return [{
json: {
keys: Object.keys(obj), // ["name", "age", "city"]
values: Object.values(obj), // ["John", 30, "NYC"]
entries: Object.entries(obj), // [["name", "John"], ...]
// Check property
hasName: 'name' in obj, // true
// Merge objects
merged: Object.assign({}, obj, {country: "USA"})
}
}];
```
### Array Methods
```javascript
const arr = [1, 2, 3, 4, 5];
return [{
json: {
mapped: arr.map(x => x * 2), // [2, 4, 6, 8, 10]
filtered: arr.filter(x => x > 2), // [3, 4, 5]
reduced: arr.reduce((sum, x) => sum + x, 0), // 15
some: arr.some(x => x > 3), // true
every: arr.every(x => x > 0), // true
find: arr.find(x => x > 3), // 4
includes: arr.includes(3), // true
joined: arr.join(', ') // "1, 2, 3, 4, 5"
}
}];
```
---
## 6. Available Node.js Modules
### crypto Module
```javascript
const crypto = require('crypto');
// Hash functions
const hash = crypto.createHash('sha256')
.update('my secret text')
.digest('hex');
// MD5 hash
const md5 = crypto.createHash('md5')
.update('my text')
.digest('hex');
// Random values
const randomBytes = crypto.randomBytes(16).toString('hex');
return [{json: {hash, md5, randomBytes}}];
```
### Buffer (built-in)
```javascript
// Base64 encoding
const encoded = Buffer.from('Hello World').toString('base64');
// Base64 decoding
const decoded = Buffer.from(encoded, 'base64').toString();
// Hex encoding
const hex = Buffer.from('Hello').toString('hex');
return [{json: {encoded, decoded, hex}}];
```
### URL / URLSearchParams
```javascript
// Parse URL
const url = new URL('https://example.com/path?param1=value1&param2=value2');
// Build query string
const params = new URLSearchParams({
search: 'query',
page: 1,
limit: 10
});
return [{
json: {
host: url.host,
pathname: url.pathname,
search: url.search,
queryString: params.toString() // "search=query&page=1&limit=10"
}
}];
```
---
## What's NOT Available
**External npm packages are NOT available:**
- ❌ axios
- ❌ lodash
- ❌ moment (use DateTime/Luxon instead)
- ❌ request
- ❌ Any other npm package
**Workaround**: Use $helpers.httpRequest() for HTTP, or add data to workflow via HTTP Request node.
---
## Summary
**Most Useful Built-ins**:
1. **$helpers.httpRequest()** - API calls without HTTP Request node
2. **DateTime** - Professional date/time handling
3. **$jmespath()** - Complex JSON queries
4. **Math, JSON, Object, Array** - Standard JavaScript utilities
**Common Patterns**:
- API calls: Use $helpers.httpRequest()
- Date operations: Use DateTime (Luxon)
- Data filtering: Use $jmespath() or JavaScript .filter()
- Persistent data: Use $getWorkflowStaticData()
- Hashing: Use crypto module
**See Also**:
- [SKILL.md](SKILL.md) - Overview
- [COMMON_PATTERNS.md](COMMON_PATTERNS.md) - Real usage examples
- [ERROR_PATTERNS.md](ERROR_PATTERNS.md) - Error prevention

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,782 @@
# Data Access Patterns - JavaScript Code Node
Comprehensive guide to accessing data in n8n Code nodes using JavaScript.
---
## Overview
In n8n Code nodes, you access data from previous nodes using built-in variables and methods. Understanding which method to use is critical for correct workflow execution.
**Data Access Priority** (by common usage):
1. **`$input.all()`** - Most common - Batch operations, aggregations
2. **`$input.first()`** - Very common - Single item operations
3. **`$input.item`** - Common - Each Item mode only
4. **`$node["NodeName"].json`** - Specific node references
5. **`$json`** - Direct current item (legacy, use `$input` instead)
---
## Pattern 1: $input.all() - Process All Items
**Usage**: Most common pattern for batch processing
**When to use:**
- Processing multiple records
- Aggregating data (sum, count, average)
- Filtering arrays
- Transforming datasets
- Comparing items
- Sorting or ranking
### Basic Usage
```javascript
// Get all items from previous node
const allItems = $input.all();
// allItems is an array of objects like:
// [
// {json: {id: 1, name: "Alice"}},
// {json: {id: 2, name: "Bob"}}
// ]
console.log(`Received ${allItems.length} items`);
return allItems;
```
### Example 1: Filter Active Items
```javascript
const allItems = $input.all();
// Filter only active items
const activeItems = allItems.filter(item => item.json.status === 'active');
return activeItems;
```
### Example 2: Transform All Items
```javascript
const allItems = $input.all();
// Map to new structure
const transformed = allItems.map(item => ({
json: {
id: item.json.id,
fullName: `${item.json.firstName} ${item.json.lastName}`,
email: item.json.email,
processedAt: new Date().toISOString()
}
}));
return transformed;
```
### Example 3: Aggregate Data
```javascript
const allItems = $input.all();
// Calculate total
const total = allItems.reduce((sum, item) => {
return sum + (item.json.amount || 0);
}, 0);
return [{
json: {
total,
count: allItems.length,
average: total / allItems.length
}
}];
```
### Example 4: Sort and Limit
```javascript
const allItems = $input.all();
// Get top 5 by score
const topFive = allItems
.sort((a, b) => (b.json.score || 0) - (a.json.score || 0))
.slice(0, 5);
return topFive.map(item => ({json: item.json}));
```
### Example 5: Group By Category
```javascript
const allItems = $input.all();
// Group items by category
const grouped = {};
for (const item of allItems) {
const category = item.json.category || 'Uncategorized';
if (!grouped[category]) {
grouped[category] = [];
}
grouped[category].push(item.json);
}
// Convert to array format
return Object.entries(grouped).map(([category, items]) => ({
json: {
category,
items,
count: items.length
}
}));
```
### Example 6: Deduplicate by ID
```javascript
const allItems = $input.all();
// Remove duplicates by ID
const seen = new Set();
const unique = [];
for (const item of allItems) {
const id = item.json.id;
if (!seen.has(id)) {
seen.add(id);
unique.push(item);
}
}
return unique;
```
---
## Pattern 2: $input.first() - Get First Item
**Usage**: Very common for single-item operations
**When to use:**
- Previous node returns single object
- Working with API responses
- Getting initial/first data point
- Configuration or metadata access
### Basic Usage
```javascript
// Get first item from previous node
const firstItem = $input.first();
// Access the JSON data
const data = firstItem.json;
console.log('First item:', data);
return [{json: data}];
```
### Example 1: Process Single API Response
```javascript
// Get API response (typically single object)
const response = $input.first().json;
// Extract what you need
return [{
json: {
userId: response.data.user.id,
userName: response.data.user.name,
status: response.status,
fetchedAt: new Date().toISOString()
}
}];
```
### Example 2: Transform Single Object
```javascript
const data = $input.first().json;
// Transform structure
return [{
json: {
id: data.id,
contact: {
email: data.email,
phone: data.phone
},
address: {
street: data.street,
city: data.city,
zip: data.zip
}
}
}];
```
### Example 3: Validate Single Item
```javascript
const item = $input.first().json;
// Validation logic
const isValid = item.email && item.email.includes('@');
return [{
json: {
...item,
valid: isValid,
validatedAt: new Date().toISOString()
}
}];
```
### Example 4: Extract Nested Data
```javascript
const response = $input.first().json;
// Navigate nested structure
const users = response.data?.users || [];
return users.map(user => ({
json: {
id: user.id,
name: user.profile?.name || 'Unknown',
email: user.contact?.email || 'no-email'
}
}));
```
### Example 5: Combine with Other Methods
```javascript
// Get first item's data
const firstData = $input.first().json;
// Use it to filter all items
const allItems = $input.all();
const matching = allItems.filter(item =>
item.json.category === firstData.targetCategory
);
return matching;
```
---
## Pattern 3: $input.item - Current Item (Each Item Mode)
**Usage**: Common in "Run Once for Each Item" mode
**When to use:**
- Mode is set to "Run Once for Each Item"
- Need to process items independently
- Per-item API calls or validations
- Item-specific error handling
**IMPORTANT**: Only use in "Each Item" mode. Will be undefined in "All Items" mode.
### Basic Usage
```javascript
// In "Run Once for Each Item" mode
const currentItem = $input.item;
const data = currentItem.json;
console.log('Processing item:', data.id);
return [{
json: {
...data,
processed: true
}
}];
```
### Example 1: Add Processing Metadata
```javascript
const item = $input.item;
return [{
json: {
...item.json,
processed: true,
processedAt: new Date().toISOString(),
processingDuration: Math.random() * 1000 // Simulated duration
}
}];
```
### Example 2: Per-Item Validation
```javascript
const item = $input.item;
const data = item.json;
// Validate this specific item
const errors = [];
if (!data.email) errors.push('Email required');
if (!data.name) errors.push('Name required');
if (data.age && data.age < 18) errors.push('Must be 18+');
return [{
json: {
...data,
valid: errors.length === 0,
errors: errors.length > 0 ? errors : undefined
}
}];
```
### Example 3: Item-Specific API Call
```javascript
const item = $input.item;
const userId = item.json.userId;
// Make API call specific to this item
const response = await $helpers.httpRequest({
method: 'GET',
url: `https://api.example.com/users/${userId}/details`
});
return [{
json: {
...item.json,
details: response
}
}];
```
### Example 4: Conditional Processing
```javascript
const item = $input.item;
const data = item.json;
// Process based on item type
if (data.type === 'premium') {
return [{
json: {
...data,
discount: 0.20,
tier: 'premium'
}
}];
} else {
return [{
json: {
...data,
discount: 0.05,
tier: 'standard'
}
}];
}
```
---
## Pattern 4: $node - Reference Other Nodes
**Usage**: Less common, but powerful for specific scenarios
**When to use:**
- Need data from specific named node
- Combining data from multiple nodes
- Accessing metadata about workflow execution
### Basic Usage
```javascript
// Get output from specific node
const webhookData = $node["Webhook"].json;
const apiData = $node["HTTP Request"].json;
return [{
json: {
fromWebhook: webhookData,
fromAPI: apiData
}
}];
```
### Example 1: Combine Multiple Sources
```javascript
// Reference multiple nodes
const webhook = $node["Webhook"].json;
const database = $node["Postgres"].json;
const api = $node["HTTP Request"].json;
return [{
json: {
combined: {
webhook: webhook.body,
dbRecords: database.length,
apiResponse: api.status
},
processedAt: new Date().toISOString()
}
}];
```
### Example 2: Compare Across Nodes
```javascript
const oldData = $node["Get Old Data"].json;
const newData = $node["Get New Data"].json;
// Compare
const changes = {
added: newData.filter(n => !oldData.find(o => o.id === n.id)),
removed: oldData.filter(o => !newData.find(n => n.id === o.id)),
modified: newData.filter(n => {
const old = oldData.find(o => o.id === n.id);
return old && JSON.stringify(old) !== JSON.stringify(n);
})
};
return [{
json: {
changes,
summary: {
added: changes.added.length,
removed: changes.removed.length,
modified: changes.modified.length
}
}
}];
```
### Example 3: Access Node Metadata
```javascript
// Get data from specific execution path
const ifTrueBranch = $node["IF True"].json;
const ifFalseBranch = $node["IF False"].json;
// Use whichever branch executed
const result = ifTrueBranch || ifFalseBranch || {};
return [{json: result}];
```
---
## Critical: Webhook Data Structure
**MOST COMMON MISTAKE**: Forgetting webhook data is nested under `.body`
### The Problem
Webhook node wraps all incoming data under a `body` property. This catches many developers by surprise.
### Structure
```javascript
// Webhook node output structure:
{
"headers": {
"content-type": "application/json",
"user-agent": "...",
// ... other headers
},
"params": {},
"query": {},
"body": {
// ← YOUR DATA IS HERE
"name": "Alice",
"email": "alice@example.com",
"message": "Hello!"
}
}
```
### Wrong vs Right
```javascript
// ❌ WRONG: Trying to access directly
const name = $json.name; // undefined
const email = $json.email; // undefined
// ✅ CORRECT: Access via .body
const name = $json.body.name; // "Alice"
const email = $json.body.email; // "alice@example.com"
// ✅ CORRECT: Extract body first
const webhookData = $json.body;
const name = webhookData.name; // "Alice"
const email = webhookData.email; // "alice@example.com"
```
### Example: Full Webhook Processing
```javascript
// Get webhook data from previous node
const webhookOutput = $input.first().json;
// Access the actual payload
const payload = webhookOutput.body;
// Access headers if needed
const contentType = webhookOutput.headers['content-type'];
// Access query parameters if needed
const apiKey = webhookOutput.query.api_key;
// Process the actual data
return [{
json: {
// Data from webhook body
userName: payload.name,
userEmail: payload.email,
message: payload.message,
// Metadata
receivedAt: new Date().toISOString(),
contentType: contentType,
authenticated: !!apiKey
}
}];
```
### POST Data, Query Params, and Headers
```javascript
const webhook = $input.first().json;
return [{
json: {
// POST body data
formData: webhook.body,
// Query parameters (?key=value)
queryParams: webhook.query,
// HTTP headers
userAgent: webhook.headers['user-agent'],
contentType: webhook.headers['content-type'],
// Request metadata
method: webhook.method, // POST, GET, etc.
url: webhook.url
}
}];
```
### Common Webhook Scenarios
```javascript
// Scenario 1: Form submission
const formData = $json.body;
const name = formData.name;
const email = formData.email;
// Scenario 2: JSON API webhook
const apiPayload = $json.body;
const eventType = apiPayload.event;
const data = apiPayload.data;
// Scenario 3: Query parameters
const apiKey = $json.query.api_key;
const userId = $json.query.user_id;
// Scenario 4: Headers
const authorization = $json.headers['authorization'];
const signature = $json.headers['x-signature'];
```
---
## Choosing the Right Pattern
### Decision Tree
```
Do you need ALL items from previous node?
├─ YES → Use $input.all()
│
└─ NO → Do you need just the FIRST item?
├─ YES → Use $input.first()
│
└─ NO → Are you in "Each Item" mode?
├─ YES → Use $input.item
│
└─ NO → Do you need specific node data?
├─ YES → Use $node["NodeName"]
└─ NO → Use $input.first() (default)
```
### Quick Reference Table
| Scenario | Use This | Example |
|----------|----------|---------|
| Sum all amounts | `$input.all()` | `allItems.reduce((sum, i) => sum + i.json.amount, 0)` |
| Get API response | `$input.first()` | `$input.first().json.data` |
| Process each independently | `$input.item` | `$input.item.json` (Each Item mode) |
| Combine two nodes | `$node["Name"]` | `$node["API"].json` |
| Filter array | `$input.all()` | `allItems.filter(i => i.json.active)` |
| Transform single object | `$input.first()` | `{...input.first().json, new: true}` |
| Webhook data | `$input.first()` | `$input.first().json.body` |
---
## Common Mistakes
### Mistake 1: Using $json Without Context
```javascript
// ❌ WRONG: $json is ambiguous
const value = $json.field;
// ✅ CORRECT: Be explicit
const value = $input.first().json.field;
```
### Mistake 2: Forgetting .json Property
```javascript
// ❌ WRONG: Trying to access fields on item object
const items = $input.all();
const names = items.map(item => item.name); // undefined
// ✅ CORRECT: Access via .json
const names = items.map(item => item.json.name);
```
### Mistake 3: Using $input.item in All Items Mode
```javascript
// ❌ WRONG: $input.item is undefined in "All Items" mode
const data = $input.item.json; // Error!
// ✅ CORRECT: Use appropriate method
const data = $input.first().json; // Or $input.all()
```
### Mistake 4: Not Handling Empty Arrays
```javascript
// ❌ WRONG: Crashes if no items
const first = $input.all()[0].json;
// ✅ CORRECT: Check length first
const items = $input.all();
if (items.length === 0) {
return [];
}
const first = items[0].json;
// ✅ ALSO CORRECT: Use $input.first()
const first = $input.first().json; // Built-in safety
```
### Mistake 5: Modifying Original Data
```javascript
// ❌ RISKY: Mutating original
const items = $input.all();
items[0].json.modified = true; // Modifies original
return items;
// ✅ SAFE: Create new objects
const items = $input.all();
return items.map(item => ({
json: {
...item.json,
modified: true
}
}));
```
---
## Advanced Patterns
### Pattern: Pagination Handling
```javascript
const currentPage = $input.all();
const pageNumber = $node["Set Page"].json.page || 1;
// Combine with previous pages
const allPreviousPages = $node["Accumulator"]?.json.accumulated || [];
return [{
json: {
accumulated: [...allPreviousPages, ...currentPage],
currentPage: pageNumber,
totalItems: allPreviousPages.length + currentPage.length
}
}];
```
### Pattern: Conditional Node Reference
```javascript
// Access different nodes based on condition
const condition = $input.first().json.type;
let data;
if (condition === 'api') {
data = $node["API Response"].json;
} else if (condition === 'database') {
data = $node["Database"].json;
} else {
data = $node["Default"].json;
}
return [{json: data}];
```
### Pattern: Multi-Node Aggregation
```javascript
// Collect data from multiple named nodes
const sources = ['Source1', 'Source2', 'Source3'];
const allData = [];
for (const source of sources) {
const nodeData = $node[source]?.json;
if (nodeData) {
allData.push({
source,
data: nodeData
});
}
}
return allData.map(item => ({json: item}));
```
---
## Summary
**Most Common Patterns**:
1. `$input.all()` - Process multiple items, batch operations
2. `$input.first()` - Single item, API responses
3. `$input.item` - Each Item mode processing
**Critical Rule**:
- Webhook data is under `.body` property
**Best Practice**:
- Be explicit: Use `$input.first().json.field` instead of `$json.field`
- Always check for null/undefined
- Use appropriate method for your mode (All Items vs Each Item)
**See Also**:
- [SKILL.md](SKILL.md) - Overview and quick start
- [COMMON_PATTERNS.md](COMMON_PATTERNS.md) - Production patterns
- [ERROR_PATTERNS.md](ERROR_PATTERNS.md) - Avoid common mistakes

View File

@@ -0,0 +1,763 @@
# Error Patterns - JavaScript Code Node
Complete guide to avoiding the most common Code node errors.
---
## Overview
This guide covers the **top 5 error patterns** encountered in n8n Code nodes. Understanding and avoiding these errors will save you significant debugging time.
**Error Frequency**:
1. Empty Code / Missing Return - **38% of failures**
2. Expression Syntax Confusion - **8% of failures**
3. Incorrect Return Wrapper - **5% of failures**
4. Unmatched Expression Brackets - **6% of failures**
5. Missing Null Checks - **Common runtime error**
---
## Error #1: Empty Code or Missing Return Statement
**Frequency**: Most common error (38% of all validation failures)
**What Happens**:
- Workflow execution fails
- Next nodes receive no data
- Error: "Code cannot be empty" or "Code must return data"
### The Problem
```javascript
// ❌ ERROR: No code at all
// (Empty code field)
```
```javascript
// ❌ ERROR: Code executes but doesn't return anything
const items = $input.all();
// Process items
for (const item of items) {
console.log(item.json.name);
}
// Forgot to return!
```
```javascript
// ❌ ERROR: Early return path exists, but not all paths return
const items = $input.all();
if (items.length === 0) {
return []; // ✅ This path returns
}
// Process items
const processed = items.map(item => ({json: item.json}));
// ❌ Forgot to return processed!
```
### The Solution
```javascript
// ✅ CORRECT: Always return data
const items = $input.all();
// Process items
const processed = items.map(item => ({
json: {
...item.json,
processed: true
}
}));
return processed; // ✅ Return statement present
```
```javascript
// ✅ CORRECT: Return empty array if no items
const items = $input.all();
if (items.length === 0) {
return []; // Valid: empty array when no data
}
// Process and return
return items.map(item => ({json: item.json}));
```
```javascript
// ✅ CORRECT: All code paths return
const items = $input.all();
if (items.length === 0) {
return [];
} else if (items.length === 1) {
return [{json: {single: true, data: items[0].json}}];
} else {
return items.map(item => ({json: item.json}));
}
// All paths covered
```
### Checklist
- [ ] Code field is not empty
- [ ] Return statement exists
- [ ] ALL code paths return data (if/else branches)
- [ ] Return format is correct (`[{json: {...}}]`)
- [ ] Return happens even on errors (use try-catch)
---
## Error #2: Expression Syntax Confusion
**Frequency**: 8% of validation failures
**What Happens**:
- Syntax error in code execution
- Error: "Unexpected token" or "Expression syntax is not valid in Code nodes"
- Template variables not evaluated
### The Problem
n8n has TWO distinct syntaxes:
1. **Expression syntax** `{{ }}` - Used in OTHER nodes (Set, IF, HTTP Request)
2. **JavaScript** - Used in CODE nodes (no `{{ }}`)
Many developers mistakenly use expression syntax inside Code nodes.
```javascript
// ❌ WRONG: Using n8n expression syntax in Code node
const userName = "{{ $json.name }}";
const userEmail = "{{ $json.body.email }}";
return [{
json: {
name: userName,
email: userEmail
}
}];
// Result: Literal string "{{ $json.name }}", NOT the value!
```
```javascript
// ❌ WRONG: Trying to evaluate expressions
const value = "{{ $now.toFormat('yyyy-MM-dd') }}";
```
### The Solution
```javascript
// ✅ CORRECT: Use JavaScript directly (no {{ }})
const userName = $json.name;
const userEmail = $json.body.email;
return [{
json: {
name: userName,
email: userEmail
}
}];
```
```javascript
// ✅ CORRECT: JavaScript template literals (use backticks)
const message = `Hello, ${$json.name}! Your email is ${$json.email}`;
return [{
json: {
greeting: message
}
}];
```
```javascript
// ✅ CORRECT: Direct variable access
const item = $input.first().json;
return [{
json: {
name: item.name,
email: item.email,
timestamp: new Date().toISOString() // JavaScript Date, not {{ }}
}
}];
```
### Comparison Table
| Context | Syntax | Example |
|---------|--------|---------|
| Set node | `{{ }}` expressions | `{{ $json.name }}` |
| IF node | `{{ }}` expressions | `{{ $json.age > 18 }}` |
| HTTP Request URL | `{{ }}` expressions | `{{ $json.userId }}` |
| **Code node** | **JavaScript** | `$json.name` |
| **Code node strings** | **Template literals** | `` `Hello ${$json.name}` `` |
### Quick Fix Guide
```javascript
// WRONG → RIGHT conversions
// ❌ "{{ $json.field }}"
// ✅ $json.field
// ❌ "{{ $now }}"
// ✅ new Date().toISOString()
// ❌ "{{ $node['HTTP Request'].json.data }}"
// ✅ $node["HTTP Request"].json.data
// ❌ `{{ $json.firstName }} {{ $json.lastName }}`
// ✅ `${$json.firstName} ${$json.lastName}`
```
---
## Error #3: Incorrect Return Wrapper Format
**Frequency**: 5% of validation failures
**What Happens**:
- Error: "Return value must be an array of objects"
- Error: "Each item must have a json property"
- Next nodes receive malformed data
### The Problem
Code nodes MUST return:
- **Array** of objects
- Each object MUST have a **`json` property**
```javascript
// ❌ WRONG: Returning object instead of array
return {
json: {
result: 'success'
}
};
// Missing array wrapper []
```
```javascript
// ❌ WRONG: Returning array without json wrapper
return [
{id: 1, name: 'Alice'},
{id: 2, name: 'Bob'}
];
// Missing json property
```
```javascript
// ❌ WRONG: Returning plain value
return "processed";
```
```javascript
// ❌ WRONG: Returning items without mapping
return $input.all();
// Works if items already have json property, but not guaranteed
```
```javascript
// ❌ WRONG: Incomplete structure
return [{data: {result: 'success'}}];
// Should be {json: {...}}, not {data: {...}}
```
### The Solution
```javascript
// ✅ CORRECT: Single result
return [{
json: {
result: 'success',
timestamp: new Date().toISOString()
}
}];
```
```javascript
// ✅ CORRECT: Multiple results
return [
{json: {id: 1, name: 'Alice'}},
{json: {id: 2, name: 'Bob'}},
{json: {id: 3, name: 'Carol'}}
];
```
```javascript
// ✅ CORRECT: Transforming array
const items = $input.all();
return items.map(item => ({
json: {
id: item.json.id,
name: item.json.name,
processed: true
}
}));
```
```javascript
// ✅ CORRECT: Empty result
return [];
// Valid when no data to return
```
```javascript
// ✅ CORRECT: Conditional returns
if (shouldProcess) {
return [{json: {result: 'processed'}}];
} else {
return [];
}
```
### Return Format Checklist
- [ ] Return value is an **array** `[...]`
- [ ] Each array element has **`json` property**
- [ ] Structure is `[{json: {...}}]` or `[{json: {...}}, {json: {...}}]`
- [ ] NOT `{json: {...}}` (missing array wrapper)
- [ ] NOT `[{...}]` (missing json property)
### Common Scenarios
```javascript
// Scenario 1: Single object from API
const response = $input.first().json;
// ✅ CORRECT
return [{json: response}];
// ❌ WRONG
return {json: response};
// Scenario 2: Array of objects
const users = $input.all();
// ✅ CORRECT
return users.map(user => ({json: user.json}));
// ❌ WRONG
return users; // Risky - depends on existing structure
// Scenario 3: Computed result
const total = $input.all().reduce((sum, item) => sum + item.json.amount, 0);
// ✅ CORRECT
return [{json: {total}}];
// ❌ WRONG
return {total};
// Scenario 4: No results
// ✅ CORRECT
return [];
// ❌ WRONG
return null;
```
---
## Error #4: Unmatched Expression Brackets
**Frequency**: 6% of validation failures
**What Happens**:
- Parsing error during save
- Error: "Unmatched expression brackets"
- Code appears correct but fails validation
### The Problem
This error typically occurs when:
1. Strings contain unbalanced quotes
2. Multi-line strings with special characters
3. Template literals with nested brackets
```javascript
// ❌ WRONG: Unescaped quote in string
const message = "It's a nice day";
// Single quote breaks string
```
```javascript
// ❌ WRONG: Unbalanced brackets in regex
const pattern = /\{(\w+)\}/; // JSON storage issue
```
```javascript
// ❌ WRONG: Multi-line string with quotes
const html = "
<div class="container">
<p>Hello</p>
</div>
";
// Quote balance issues
```
### The Solution
```javascript
// ✅ CORRECT: Escape quotes
const message = "It\\'s a nice day";
// Or use different quotes
const message = "It's a nice day"; // Double quotes work
```
```javascript
// ✅ CORRECT: Escape regex properly
const pattern = /\\{(\\w+)\\}/;
```
```javascript
// ✅ CORRECT: Template literals for multi-line
const html = `
<div class="container">
<p>Hello</p>
</div>
`;
// Backticks handle multi-line and quotes
```
```javascript
// ✅ CORRECT: Escape backslashes
const path = "C:\\\\Users\\\\Documents\\\\file.txt";
```
### Escaping Guide
| Character | Escape As | Example |
|-----------|-----------|---------|
| Single quote in single-quoted string | `\\'` | `'It\\'s working'` |
| Double quote in double-quoted string | `\\"` | `"She said \\"hello\\""` |
| Backslash | `\\\\` | `"C:\\\\path"` |
| Newline | `\\n` | `"Line 1\\nLine 2"` |
| Tab | `\\t` | `"Column1\\tColumn2"` |
### Best Practices
```javascript
// ✅ BEST: Use template literals for complex strings
const message = `User ${name} said: "Hello!"`;
// ✅ BEST: Use template literals for HTML
const html = `
<div class="${className}">
<h1>${title}</h1>
<p>${content}</p>
</div>
`;
// ✅ BEST: Use template literals for JSON
const jsonString = `{
"name": "${name}",
"email": "${email}"
}`;
```
---
## Error #5: Missing Null Checks / Undefined Access
**Frequency**: Very common runtime error
**What Happens**:
- Workflow execution stops
- Error: "Cannot read property 'X' of undefined"
- Error: "Cannot read property 'X' of null"
- Crashes on missing data
### The Problem
```javascript
// ❌ WRONG: No null check - crashes if user doesn't exist
const email = item.json.user.email;
```
```javascript
// ❌ WRONG: Assumes array has items
const firstItem = $input.all()[0].json;
```
```javascript
// ❌ WRONG: Assumes nested property exists
const city = $json.address.city;
```
```javascript
// ❌ WRONG: No validation before array operations
const names = $json.users.map(user => user.name);
```
### The Solution
```javascript
// ✅ CORRECT: Optional chaining
const email = item.json?.user?.email || 'no-email@example.com';
```
```javascript
// ✅ CORRECT: Check array length
const items = $input.all();
if (items.length === 0) {
return [];
}
const firstItem = items[0].json;
```
```javascript
// ✅ CORRECT: Guard clauses
const data = $input.first().json;
if (!data.address) {
return [{json: {error: 'No address provided'}}];
}
const city = data.address.city;
```
```javascript
// ✅ CORRECT: Default values
const users = $json.users || [];
const names = users.map(user => user.name || 'Unknown');
```
```javascript
// ✅ CORRECT: Try-catch for risky operations
try {
const email = item.json.user.email.toLowerCase();
return [{json: {email}}];
} catch (error) {
return [{
json: {
error: 'Invalid user data',
details: error.message
}
}];
}
```
### Safe Access Patterns
```javascript
// Pattern 1: Optional chaining (modern, recommended)
const value = data?.nested?.property?.value;
// Pattern 2: Logical OR with default
const value = data.property || 'default';
// Pattern 3: Ternary check
const value = data.property ? data.property : 'default';
// Pattern 4: Guard clause
if (!data.property) {
return [];
}
const value = data.property;
// Pattern 5: Try-catch
try {
const value = data.nested.property.value;
} catch (error) {
const value = 'default';
}
```
### Webhook Data Safety
```javascript
// Webhook data requires extra safety
// ❌ RISKY: Assumes all fields exist
const name = $json.body.user.name;
const email = $json.body.user.email;
// ✅ SAFE: Check each level
const body = $json.body || {};
const user = body.user || {};
const name = user.name || 'Unknown';
const email = user.email || 'no-email';
// ✅ BETTER: Optional chaining
const name = $json.body?.user?.name || 'Unknown';
const email = $json.body?.user?.email || 'no-email';
```
### Array Safety
```javascript
// ❌ RISKY: No length check
const items = $input.all();
const firstId = items[0].json.id;
// ✅ SAFE: Check length
const items = $input.all();
if (items.length > 0) {
const firstId = items[0].json.id;
} else {
// Handle empty case
return [];
}
// ✅ BETTER: Use $input.first()
const firstItem = $input.first();
const firstId = firstItem.json.id; // Built-in safety
```
### Object Property Safety
```javascript
// ❌ RISKY: Direct access
const config = $json.settings.advanced.timeout;
// ✅ SAFE: Step by step with defaults
const settings = $json.settings || {};
const advanced = settings.advanced || {};
const timeout = advanced.timeout || 30000;
// ✅ BETTER: Optional chaining
const timeout = $json.settings?.advanced?.timeout ?? 30000;
// Note: ?? (nullish coalescing) vs || (logical OR)
```
---
## Error Prevention Checklist
Use this checklist before deploying Code nodes:
### Code Structure
- [ ] Code field is not empty
- [ ] Return statement exists
- [ ] All code paths return data
### Return Format
- [ ] Returns array: `[...]`
- [ ] Each item has `json` property: `{json: {...}}`
- [ ] Format is `[{json: {...}}]`
### Syntax
- [ ] No `{{ }}` expression syntax (use JavaScript)
- [ ] Template literals use backticks: `` `${variable}` ``
- [ ] All quotes and brackets balanced
- [ ] Strings properly escaped
### Data Safety
- [ ] Null checks for optional properties
- [ ] Array length checks before access
- [ ] Webhook data accessed via `.body`
- [ ] Try-catch for risky operations
- [ ] Default values for missing data
### Testing
- [ ] Test with empty input
- [ ] Test with missing fields
- [ ] Test with unexpected data types
- [ ] Check browser console for errors
---
## Quick Error Reference
| Error Message | Likely Cause | Fix |
|---------------|--------------|-----|
| "Code cannot be empty" | Empty code field | Add meaningful code |
| "Code must return data" | Missing return statement | Add `return [...]` |
| "Return value must be an array" | Returning object instead of array | Wrap in `[...]` |
| "Each item must have json property" | Missing `json` wrapper | Use `{json: {...}}` |
| "Unexpected token" | Expression syntax `{{ }}` in code | Remove `{{ }}`, use JavaScript |
| "Cannot read property X of undefined" | Missing null check | Use optional chaining `?.` |
| "Cannot read property X of null" | Null value access | Add guard clause or default |
| "Unmatched expression brackets" | Quote/bracket imbalance | Check string escaping |
---
## Debugging Tips
### 1. Use console.log()
```javascript
const items = $input.all();
console.log('Items count:', items.length);
console.log('First item:', items[0]);
// Check browser console (F12) for output
```
### 2. Return Intermediate Results
```javascript
// Debug by returning current state
const items = $input.all();
const processed = items.map(item => ({json: item.json}));
// Return to see what you have
return processed;
```
### 3. Try-Catch for Troubleshooting
```javascript
try {
// Your code here
const result = riskyOperation();
return [{json: {result}}];
} catch (error) {
// See what failed
return [{
json: {
error: error.message,
stack: error.stack
}
}];
}
```
### 4. Validate Input Structure
```javascript
const items = $input.all();
// Check what you received
console.log('Input structure:', JSON.stringify(items[0], null, 2));
// Then process
```
---
## Summary
**Top 5 Errors to Avoid**:
1. **Empty code / missing return** (38%) - Always return data
2. **Expression syntax `{{ }}`** (8%) - Use JavaScript, not expressions
3. **Wrong return format** (5%) - Always `[{json: {...}}]`
4. **Unmatched brackets** (6%) - Escape strings properly
5. **Missing null checks** - Use optional chaining `?.`
**Quick Prevention**:
- Return `[{json: {...}}]` format
- Use JavaScript, NOT `{{ }}` expressions
- Check for null/undefined before accessing
- Test with empty and invalid data
- Use browser console for debugging
**See Also**:
- [SKILL.md](SKILL.md) - Overview and best practices
- [DATA_ACCESS.md](DATA_ACCESS.md) - Safe data access patterns
- [COMMON_PATTERNS.md](COMMON_PATTERNS.md) - Working examples

View File

@@ -0,0 +1,350 @@
# n8n Code JavaScript
Expert guidance for writing JavaScript code in n8n Code nodes.
---
## Purpose
Teaches how to write effective JavaScript in n8n Code nodes, avoid common errors, and use built-in functions effectively.
---
## Activates On
**Trigger keywords**:
- "javascript code node"
- "write javascript in n8n"
- "code node javascript"
- "$input syntax"
- "$json syntax"
- "$helpers.httpRequest"
- "DateTime luxon"
- "code node error"
- "webhook data code"
- "return format code node"
**Common scenarios**:
- Writing JavaScript code in Code nodes
- Troubleshooting Code node errors
- Making HTTP requests from code
- Working with dates and times
- Accessing webhook data
- Choosing between All Items and Each Item mode
---
## What You'll Learn
### Quick Start
- Mode selection (All Items vs Each Item)
- Data access patterns ($input.all(), $input.first(), $input.item)
- Correct return format: `[{json: {...}}]`
- Webhook data structure (.body nesting)
- Built-in functions overview
### Data Access Mastery
- $input.all() - Batch operations (most common)
- $input.first() - Single item operations
- $input.item - Each Item mode processing
- $node - Reference other workflow nodes
- **Critical gotcha**: Webhook data under `.body`
### Common Patterns (Production-Tested)
1. Multi-source Data Aggregation
2. Regex Filtering & Pattern Matching
3. Markdown Parsing & Structured Extraction
4. JSON Comparison & Validation
5. CRM Data Transformation
6. Release Information Processing
7. Array Transformation with Context
8. Slack Block Kit Formatting
9. Top N Filtering & Ranking
10. String Aggregation & Reporting
### Error Prevention
Top 5 errors to avoid:
1. **Empty code / missing return** (38% of failures)
2. **Expression syntax confusion** (using `{{}}` in code)
3. **Incorrect return format** (missing array wrapper or json property)
4. **Unmatched brackets** (string escaping issues)
5. **Missing null checks** (crashes on undefined)
### Built-in Functions
- **$helpers.httpRequest()** - Make HTTP requests
- **DateTime (Luxon)** - Advanced date/time operations
- **$jmespath()** - Query JSON structures
- **$getWorkflowStaticData()** - Persistent storage
- Standard JavaScript globals (Math, JSON, console)
- Available Node.js modules (crypto, Buffer, URL)
---
## File Structure
```
n8n-code-javascript/
├── SKILL.md (500 lines)
│ Overview, quick start, mode selection, best practices
│ - Mode selection guide (All Items vs Each Item)
│ - Data access patterns overview
│ - Return format requirements
│ - Critical webhook gotcha
│ - Error prevention overview
│ - Quick reference checklist
│
├── DATA_ACCESS.md (400 lines)
│ Complete data access patterns
│ - $input.all() - Most common (26% usage)
│ - $input.first() - Very common (25% usage)
│ - $input.item - Each Item mode (19% usage)
│ - $node - Reference other nodes
│ - Webhook data structure (.body nesting)
│ - Choosing the right pattern
│ - Common mistakes to avoid
│
├── COMMON_PATTERNS.md (600 lines)
│ 10 production-tested patterns
│ - Pattern 1: Multi-source Aggregation
│ - Pattern 2: Regex Filtering
│ - Pattern 3: Markdown Parsing
│ - Pattern 4: JSON Comparison
│ - Pattern 5: CRM Transformation
│ - Pattern 6: Release Processing
│ - Pattern 7: Array Transformation
│ - Pattern 8: Slack Block Kit
│ - Pattern 9: Top N Filtering
│ - Pattern 10: String Aggregation
│ - Pattern selection guide
│
├── ERROR_PATTERNS.md (450 lines)
│ Top 5 errors with solutions
│ - Error #1: Empty Code / Missing Return (38%)
│ - Error #2: Expression Syntax Confusion (8%)
│ - Error #3: Incorrect Return Wrapper (5%)
│ - Error #4: Unmatched Brackets (6%)
│ - Error #5: Missing Null Checks
│ - Error prevention checklist
│ - Quick error reference
│ - Debugging tips
│
├── BUILTIN_FUNCTIONS.md (450 lines)
│ Complete built-in function reference
│ - $helpers.httpRequest() API reference
│ - DateTime (Luxon) complete guide
│ - $jmespath() JSON querying
│ - $getWorkflowStaticData() persistent storage
│ - Standard JavaScript globals
│ - Available Node.js modules
│ - What's NOT available
│
└── README.md (this file)
Skill metadata and overview
```
**Total**: ~2,400 lines across 6 files
---
## Coverage
### Mode Selection
- **Run Once for All Items** - Recommended for 95% of use cases
- **Run Once for Each Item** - Specialized cases only
- Decision guide and performance implications
### Data Access
- Most common patterns with usage statistics
- Webhook data structure (critical .body gotcha)
- Safe access patterns with null checks
- When to use which pattern
### Error Prevention
- Top 5 errors covering 62%+ of all failures
- Clear wrong vs right examples
- Error prevention checklist
- Debugging tips and console.log usage
### Production Patterns
- 10 patterns from real workflows
- Complete working examples
- Use cases and key techniques
- Pattern selection guide
### Built-in Functions
- Complete $helpers.httpRequest() reference
- DateTime/Luxon operations (formatting, parsing, arithmetic)
- $jmespath() for JSON queries
- Persistent storage with $getWorkflowStaticData()
- Standard JavaScript and Node.js modules
---
## Critical Gotchas Highlighted
### #1: Webhook Data Structure
**MOST COMMON MISTAKE**: Webhook data is under `.body`
```javascript
// ❌ WRONG
const name = $json.name;
// ✅ CORRECT
const name = $json.body.name;
```
### #2: Return Format
**CRITICAL**: Must return array with json property
```javascript
// ❌ WRONG
return {json: {result: 'success'}};
// ✅ CORRECT
return [{json: {result: 'success'}}];
```
### #3: Expression Syntax
**Don't use `{{}}` in Code nodes**
```javascript
// ❌ WRONG
const value = "{{ $json.field }}";
// ✅ CORRECT
const value = $json.field;
```
---
## Integration with Other Skills
### n8n Expression Syntax
- **Distinction**: Expressions use `{{}}` in OTHER nodes
- **Code nodes**: Use JavaScript directly (no `{{}}`)
- **When to use each**: Code vs expressions decision guide
### n8n MCP Tools Expert
- Find Code node: `search_nodes({query: "code"})`
- Get configuration: `get_node_essentials("nodes-base.code")`
- Validate code: `validate_node_operation()`
### n8n Node Configuration
- Mode selection (All Items vs Each Item)
- Language selection (JavaScript vs Python)
- Understanding property dependencies
### n8n Workflow Patterns
- Code nodes in transformation step
- Webhook → Code → API pattern
- Error handling in workflows
### n8n Validation Expert
- Validate Code node configuration
- Handle validation errors
- Auto-fix common issues
---
## When to Use Code Node
**Use Code node when:**
- ✅ Complex transformations requiring multiple steps
- ✅ Custom calculations or business logic
- ✅ Recursive operations
- ✅ API response parsing with complex structure
- ✅ Multi-step conditionals
- ✅ Data aggregation across items
**Consider other nodes when:**
- ❌ Simple field mapping → Use **Set** node
- ❌ Basic filtering → Use **Filter** node
- ❌ Simple conditionals → Use **IF** or **Switch** node
- ❌ HTTP requests only → Use **HTTP Request** node
**Code node excels at**: Complex logic that would require chaining many simple nodes
---
## Success Metrics
**Before this skill**:
- Users confused by mode selection
- Frequent return format errors
- Expression syntax mistakes
- Webhook data access failures
- Missing null check crashes
**After this skill**:
- Clear mode selection guidance
- Understanding of return format
- JavaScript vs expression distinction
- Correct webhook data access
- Safe null-handling patterns
- Production-ready code patterns
---
## Quick Reference
### Essential Rules
1. Choose "All Items" mode (recommended)
2. Access data: `$input.all()`, `$input.first()`, `$input.item`
3. **MUST return**: `[{json: {...}}]` format
4. **Webhook data**: Under `.body` property
5. **No `{{}}` syntax**: Use JavaScript directly
### Most Common Patterns
- Batch processing → $input.all() + map/filter
- Single item → $input.first()
- Aggregation → reduce()
- HTTP requests → $helpers.httpRequest()
- Date handling → DateTime (Luxon)
### Error Prevention
- Always return data
- Check for null/undefined
- Use try-catch for risky operations
- Test with empty input
- Use console.log() for debugging
---
## Related Documentation
- **n8n Code Node Guide**: https://docs.n8n.io/code/code-node/
- **Built-in Methods Reference**: https://docs.n8n.io/code-examples/methods-variables-reference/
- **Luxon Documentation**: https://moment.github.io/luxon/
---
## Evaluations
**5 test scenarios** covering:
1. Webhook body gotcha (most common mistake)
2. Return format error (missing array wrapper)
3. HTTP request with $helpers.httpRequest()
4. Aggregation pattern with $input.all()
5. Expression syntax confusion (using `{{}}`)
Each evaluation tests skill activation, correct guidance, and reference to appropriate documentation files.
---
## Version History
- **v1.0** (2025-01-20): Initial implementation
- SKILL.md with comprehensive overview
- DATA_ACCESS.md covering all access patterns
- COMMON_PATTERNS.md with 10 production patterns
- ERROR_PATTERNS.md covering top 5 errors
- BUILTIN_FUNCTIONS.md complete reference
- 5 evaluation scenarios
---
## Author
Conceived by Romuald Członkowski - [www.aiadvisors.pl/en](https://www.aiadvisors.pl/en)
Part of the n8n-skills collection.

View File

@@ -0,0 +1,699 @@
---
name: n8n-code-javascript
description: Write JavaScript code in n8n Code nodes. Use when writing JavaScript in n8n, using $input/$json/$node syntax, making HTTP requests with $helpers, working with dates using DateTime, troubleshooting Code node errors, or choosing between Code node modes.
---
# JavaScript Code Node
Expert guidance for writing JavaScript code in n8n Code nodes.
---
## Quick Start
```javascript
// Basic template for Code nodes
const items = $input.all();
// Process data
const processed = items.map(item => ({
json: {
...item.json,
processed: true,
timestamp: new Date().toISOString()
}
}));
return processed;
```
### Essential Rules
1. **Choose "Run Once for All Items" mode** (recommended for most use cases)
2. **Access data**: `$input.all()`, `$input.first()`, or `$input.item`
3. **CRITICAL**: Must return `[{json: {...}}]` format
4. **CRITICAL**: Webhook data is under `$json.body` (not `$json` directly)
5. **Built-ins available**: $helpers.httpRequest(), DateTime (Luxon), $jmespath()
---
## Mode Selection Guide
The Code node offers two execution modes. Choose based on your use case:
### Run Once for All Items (Recommended - Default)
**Use this mode for:** 95% of use cases
- **How it works**: Code executes **once** regardless of input count
- **Data access**: `$input.all()` or `items` array
- **Best for**: Aggregation, filtering, batch processing, transformations, API calls with all data
- **Performance**: Faster for multiple items (single execution)
```javascript
// Example: Calculate total from all items
const allItems = $input.all();
const total = allItems.reduce((sum, item) => sum + (item.json.amount || 0), 0);
return [{
json: {
total,
count: allItems.length,
average: total / allItems.length
}
}];
```
**When to use:**
- ✅ Comparing items across the dataset
- ✅ Calculating totals, averages, or statistics
- ✅ Sorting or ranking items
- ✅ Deduplication
- ✅ Building aggregated reports
- ✅ Combining data from multiple items
### Run Once for Each Item
**Use this mode for:** Specialized cases only
- **How it works**: Code executes **separately** for each input item
- **Data access**: `$input.item` or `$item`
- **Best for**: Item-specific logic, independent operations, per-item validation
- **Performance**: Slower for large datasets (multiple executions)
```javascript
// Example: Add processing timestamp to each item
const item = $input.item;
return [{
json: {
...item.json,
processed: true,
processedAt: new Date().toISOString()
}
}];
```
**When to use:**
- ✅ Each item needs independent API call
- ✅ Per-item validation with different error handling
- ✅ Item-specific transformations based on item properties
- ✅ When items must be processed separately for business logic
**Decision Shortcut:**
- **Need to look at multiple items?** → Use "All Items" mode
- **Each item completely independent?** → Use "Each Item" mode
- **Not sure?** → Use "All Items" mode (you can always loop inside)
---
## Data Access Patterns
### Pattern 1: $input.all() - Most Common
**Use when**: Processing arrays, batch operations, aggregations
```javascript
// Get all items from previous node
const allItems = $input.all();
// Filter, map, reduce as needed
const valid = allItems.filter(item => item.json.status === 'active');
const mapped = valid.map(item => ({
json: {
id: item.json.id,
name: item.json.name
}
}));
return mapped;
```
### Pattern 2: $input.first() - Very Common
**Use when**: Working with single objects, API responses, first-in-first-out
```javascript
// Get first item only
const firstItem = $input.first();
const data = firstItem.json;
return [{
json: {
result: processData(data),
processedAt: new Date().toISOString()
}
}];
```
### Pattern 3: $input.item - Each Item Mode Only
**Use when**: In "Run Once for Each Item" mode
```javascript
// Current item in loop (Each Item mode only)
const currentItem = $input.item;
return [{
json: {
...currentItem.json,
itemProcessed: true
}
}];
```
### Pattern 4: $node - Reference Other Nodes
**Use when**: Need data from specific nodes in workflow
```javascript
// Get output from specific node
const webhookData = $node["Webhook"].json;
const httpData = $node["HTTP Request"].json;
return [{
json: {
combined: {
webhook: webhookData,
api: httpData
}
}
}];
```
**See**: [DATA_ACCESS.md](DATA_ACCESS.md) for comprehensive guide
---
## Critical: Webhook Data Structure
**MOST COMMON MISTAKE**: Webhook data is nested under `.body`
```javascript
// ❌ WRONG - Will return undefined
const name = $json.name;
const email = $json.email;
// ✅ CORRECT - Webhook data is under .body
const name = $json.body.name;
const email = $json.body.email;
// Or with $input
const webhookData = $input.first().json.body;
const name = webhookData.name;
```
**Why**: Webhook node wraps all request data under `body` property. This includes POST data, query parameters, and JSON payloads.
**See**: [DATA_ACCESS.md](DATA_ACCESS.md) for full webhook structure details
---
## Return Format Requirements
**CRITICAL RULE**: Always return array of objects with `json` property
### Correct Return Formats
```javascript
// ✅ Single result
return [{
json: {
field1: value1,
field2: value2
}
}];
// ✅ Multiple results
return [
{json: {id: 1, data: 'first'}},
{json: {id: 2, data: 'second'}}
];
// ✅ Transformed array
const transformed = $input.all()
.filter(item => item.json.valid)
.map(item => ({
json: {
id: item.json.id,
processed: true
}
}));
return transformed;
// ✅ Empty result (when no data to return)
return [];
// ✅ Conditional return
if (shouldProcess) {
return [{json: processedData}];
} else {
return [];
}
```
### Incorrect Return Formats
```javascript
// ❌ WRONG: Object without array wrapper
return {
json: {field: value}
};
// ❌ WRONG: Array without json wrapper
return [{field: value}];
// ❌ WRONG: Plain string
return "processed";
// ❌ WRONG: Raw data without mapping
return $input.all(); // Missing .map()
// ❌ WRONG: Incomplete structure
return [{data: value}]; // Should be {json: value}
```
**Why it matters**: Next nodes expect array format. Incorrect format causes workflow execution to fail.
**See**: [ERROR_PATTERNS.md](ERROR_PATTERNS.md) #3 for detailed error solutions
---
## Common Patterns Overview
Based on production workflows, here are the most useful patterns:
### 1. Multi-Source Data Aggregation
Combine data from multiple APIs, webhooks, or nodes
```javascript
const allItems = $input.all();
const results = [];
for (const item of allItems) {
const sourceName = item.json.name || 'Unknown';
// Parse source-specific structure
if (sourceName === 'API1' && item.json.data) {
results.push({
json: {
title: item.json.data.title,
source: 'API1'
}
});
}
}
return results;
```
### 2. Filtering with Regex
Extract patterns, mentions, or keywords from text
```javascript
const pattern = /\b([A-Z]{2,5})\b/g;
const matches = {};
for (const item of $input.all()) {
const text = item.json.text;
const found = text.match(pattern);
if (found) {
found.forEach(match => {
matches[match] = (matches[match] || 0) + 1;
});
}
}
return [{json: {matches}}];
```
### 3. Data Transformation & Enrichment
Map fields, normalize formats, add computed fields
```javascript
const items = $input.all();
return items.map(item => {
const data = item.json;
const nameParts = data.name.split(' ');
return {
json: {
first_name: nameParts[0],
last_name: nameParts.slice(1).join(' '),
email: data.email,
created_at: new Date().toISOString()
}
};
});
```
### 4. Top N Filtering & Ranking
Sort and limit results
```javascript
const items = $input.all();
const topItems = items
.sort((a, b) => (b.json.score || 0) - (a.json.score || 0))
.slice(0, 10);
return topItems.map(item => ({json: item.json}));
```
### 5. Aggregation & Reporting
Sum, count, group data
```javascript
const items = $input.all();
const total = items.reduce((sum, item) => sum + (item.json.amount || 0), 0);
return [{
json: {
total,
count: items.length,
average: total / items.length,
timestamp: new Date().toISOString()
}
}];
```
**See**: [COMMON_PATTERNS.md](COMMON_PATTERNS.md) for 10 detailed production patterns
---
## Error Prevention - Top 5 Mistakes
### #1: Empty Code or Missing Return (Most Common)
```javascript
// ❌ WRONG: No return statement
const items = $input.all();
// ... processing code ...
// Forgot to return!
// ✅ CORRECT: Always return data
const items = $input.all();
// ... processing ...
return items.map(item => ({json: item.json}));
```
### #2: Expression Syntax Confusion
```javascript
// ❌ WRONG: Using n8n expression syntax in code
const value = "{{ $json.field }}";
// ✅ CORRECT: Use JavaScript template literals
const value = `${$json.field}`;
// ✅ CORRECT: Direct access
const value = $input.first().json.field;
```
### #3: Incorrect Return Wrapper
```javascript
// ❌ WRONG: Returning object instead of array
return {json: {result: 'success'}};
// ✅ CORRECT: Array wrapper required
return [{json: {result: 'success'}}];
```
### #4: Missing Null Checks
```javascript
// ❌ WRONG: Crashes if field doesn't exist
const value = item.json.user.email;
// ✅ CORRECT: Safe access with optional chaining
const value = item.json?.user?.email || 'no-email@example.com';
// ✅ CORRECT: Guard clause
if (!item.json.user) {
return [];
}
const value = item.json.user.email;
```
### #5: Webhook Body Nesting
```javascript
// ❌ WRONG: Direct access to webhook data
const email = $json.email;
// ✅ CORRECT: Webhook data under .body
const email = $json.body.email;
```
**See**: [ERROR_PATTERNS.md](ERROR_PATTERNS.md) for comprehensive error guide
---
## Built-in Functions & Helpers
### $helpers.httpRequest()
Make HTTP requests from within code:
```javascript
const response = await $helpers.httpRequest({
method: 'GET',
url: 'https://api.example.com/data',
headers: {
'Authorization': 'Bearer token',
'Content-Type': 'application/json'
}
});
return [{json: {data: response}}];
```
### DateTime (Luxon)
Date and time operations:
```javascript
// Current time
const now = DateTime.now();
// Format dates
const formatted = now.toFormat('yyyy-MM-dd');
const iso = now.toISO();
// Date arithmetic
const tomorrow = now.plus({days: 1});
const lastWeek = now.minus({weeks: 1});
return [{
json: {
today: formatted,
tomorrow: tomorrow.toFormat('yyyy-MM-dd')
}
}];
```
### $jmespath()
Query JSON structures:
```javascript
const data = $input.first().json;
// Filter array
const adults = $jmespath(data, 'users[?age >= `18`]');
// Extract fields
const names = $jmespath(data, 'users[*].name');
return [{json: {adults, names}}];
```
**See**: [BUILTIN_FUNCTIONS.md](BUILTIN_FUNCTIONS.md) for complete reference
---
## Best Practices
### 1. Always Validate Input Data
```javascript
const items = $input.all();
// Check if data exists
if (!items || items.length === 0) {
return [];
}
// Validate structure
if (!items[0].json) {
return [{json: {error: 'Invalid input format'}}];
}
// Continue processing...
```
### 2. Use Try-Catch for Error Handling
```javascript
try {
const response = await $helpers.httpRequest({
url: 'https://api.example.com/data'
});
return [{json: {success: true, data: response}}];
} catch (error) {
return [{
json: {
success: false,
error: error.message
}
}];
}
```
### 3. Prefer Array Methods Over Loops
```javascript
// ✅ GOOD: Functional approach
const processed = $input.all()
.filter(item => item.json.valid)
.map(item => ({json: {id: item.json.id}}));
// ❌ SLOWER: Manual loop
const processed = [];
for (const item of $input.all()) {
if (item.json.valid) {
processed.push({json: {id: item.json.id}});
}
}
```
### 4. Filter Early, Process Late
```javascript
// ✅ GOOD: Filter first to reduce processing
const processed = $input.all()
.filter(item => item.json.status === 'active') // Reduce dataset first
.map(item => expensiveTransformation(item)); // Then transform
// ❌ WASTEFUL: Transform everything, then filter
const processed = $input.all()
.map(item => expensiveTransformation(item)) // Wastes CPU
.filter(item => item.json.status === 'active');
```
### 5. Use Descriptive Variable Names
```javascript
// ✅ GOOD: Clear intent
const activeUsers = $input.all().filter(item => item.json.active);
const totalRevenue = activeUsers.reduce((sum, user) => sum + user.json.revenue, 0);
// ❌ BAD: Unclear purpose
const a = $input.all().filter(item => item.json.active);
const t = a.reduce((s, u) => s + u.json.revenue, 0);
```
### 6. Debug with console.log()
```javascript
// Debug statements appear in browser console
const items = $input.all();
console.log(`Processing ${items.length} items`);
for (const item of items) {
console.log('Item data:', item.json);
// Process...
}
return result;
```
---
## When to Use Code Node
Use Code node when:
- ✅ Complex transformations requiring multiple steps
- ✅ Custom calculations or business logic
- ✅ Recursive operations
- ✅ API response parsing with complex structure
- ✅ Multi-step conditionals
- ✅ Data aggregation across items
Consider other nodes when:
- ❌ Simple field mapping → Use **Set** node
- ❌ Basic filtering → Use **Filter** node
- ❌ Simple conditionals → Use **IF** or **Switch** node
- ❌ HTTP requests only → Use **HTTP Request** node
**Code node excels at**: Complex logic that would require chaining many simple nodes
---
## Integration with Other Skills
### Works With:
**n8n Expression Syntax**:
- Expressions use `{{ }}` syntax in other nodes
- Code nodes use JavaScript directly (no `{{ }}`)
- When to use expressions vs code
**n8n MCP Tools Expert**:
- How to find Code node: `search_nodes({query: "code"})`
- Get configuration help: `get_node_essentials("nodes-base.code")`
- Validate code: `validate_node_operation()`
**n8n Node Configuration**:
- Mode selection (All Items vs Each Item)
- Language selection (JavaScript vs Python)
- Understanding property dependencies
**n8n Workflow Patterns**:
- Code nodes in transformation step
- Webhook → Code → API pattern
- Error handling in workflows
**n8n Validation Expert**:
- Validate Code node configuration
- Handle validation errors
- Auto-fix common issues
---
## Quick Reference Checklist
Before deploying Code nodes, verify:
- [ ] **Code is not empty** - Must have meaningful logic
- [ ] **Return statement exists** - Must return array of objects
- [ ] **Proper return format** - Each item: `{json: {...}}`
- [ ] **Data access correct** - Using `$input.all()`, `$input.first()`, or `$input.item`
- [ ] **No n8n expressions** - Use JavaScript template literals: `` `${value}` ``
- [ ] **Error handling** - Guard clauses for null/undefined inputs
- [ ] **Webhook data** - Access via `.body` if from webhook
- [ ] **Mode selection** - "All Items" for most cases
- [ ] **Performance** - Prefer map/filter over manual loops
- [ ] **Output consistent** - All code paths return same structure
---
## Additional Resources
### Related Files
- [DATA_ACCESS.md](DATA_ACCESS.md) - Comprehensive data access patterns
- [COMMON_PATTERNS.md](COMMON_PATTERNS.md) - 10 production-tested patterns
- [ERROR_PATTERNS.md](ERROR_PATTERNS.md) - Top 5 errors and solutions
- [BUILTIN_FUNCTIONS.md](BUILTIN_FUNCTIONS.md) - Complete built-in reference
### n8n Documentation
- Code Node Guide: https://docs.n8n.io/code/code-node/
- Built-in Methods: https://docs.n8n.io/code-examples/methods-variables-reference/
- Luxon Documentation: https://moment.github.io/luxon/
---
**Ready to write JavaScript in n8n Code nodes!** Start with simple transformations, use the error patterns guide to avoid common mistakes, and reference the pattern library for production-ready examples.

View File

@@ -0,0 +1,393 @@
# Common n8n Expression Mistakes
Complete catalog of expression errors with explanations and fixes.
---
## 1. Missing Curly Braces
**Problem**: Expression not recognized, shows as literal text
❌ **Wrong**:
```
$json.email
```
✅ **Correct**:
```
{{$json.email}}
```
**Why it fails**: n8n treats text without {{ }} as a literal string. Expressions must be wrapped to be evaluated.
**How to identify**: Field shows exact text like "$json.email" instead of actual value.
---
## 2. Webhook Body Access
**Problem**: Undefined values when accessing webhook data
❌ **Wrong**:
```
{{$json.name}}
{{$json.email}}
{{$json.message}}
```
✅ **Correct**:
```
{{$json.body.name}}
{{$json.body.email}}
{{$json.body.message}}
```
**Why it fails**: Webhook node wraps incoming data under `.body` property. The root `$json` contains headers, params, query, and body.
**Webhook structure**:
```javascript
{
"headers": {...},
"params": {...},
"query": {...},
"body": { // User data is HERE!
"name": "John",
"email": "john@example.com"
}
}
```
**How to identify**: Webhook workflow shows "undefined" for fields that are definitely being sent.
---
## 3. Spaces in Field Names
**Problem**: Syntax error or undefined value
❌ **Wrong**:
```
{{$json.first name}}
{{$json.user data.email}}
```
✅ **Correct**:
```
{{$json['first name']}}
{{$json['user data'].email}}
```
**Why it fails**: Spaces break dot notation. JavaScript interprets space as end of property name.
**How to identify**: Error message about unexpected token, or undefined when field exists.
---
## 4. Spaces in Node Names
**Problem**: Cannot access other node's data
❌ **Wrong**:
```
{{$node.HTTP Request.json.data}}
{{$node.Respond to Webhook.json}}
```
✅ **Correct**:
```
{{$node["HTTP Request"].json.data}}
{{$node["Respond to Webhook"].json}}
```
**Why it fails**: Node names are treated as object property names and need quotes when they contain spaces.
**How to identify**: Error like "Cannot read property 'Request' of undefined"
---
## 5. Incorrect Node Reference Case
**Problem**: Undefined or wrong data returned
❌ **Wrong**:
```
{{$node["http request"].json.data}} // lowercase
{{$node["Http Request"].json.data}} // wrong capitalization
```
✅ **Correct**:
```
{{$node["HTTP Request"].json.data}} // exact match
```
**Why it fails**: Node names are **case-sensitive**. Must match exactly as shown in workflow.
**How to identify**: Undefined value even though node exists and has data.
---
## 6. Double Wrapping
**Problem**: Literal {{ }} appears in output
❌ **Wrong**:
```
{{{$json.field}}}
```
✅ **Correct**:
```
{{$json.field}}
```
**Why it fails**: Only one set of {{ }} is needed. Extra braces are treated as literal characters.
**How to identify**: Output shows "{{value}}" instead of just "value".
---
## 7. Array Access with Dots
**Problem**: Syntax error or undefined
❌ **Wrong**:
```
{{$json.items.0.name}}
{{$json.users.1.email}}
```
✅ **Correct**:
```
{{$json.items[0].name}}
{{$json.users[1].email}}
```
**Why it fails**: Array indices require brackets, not dots. Number after dot is invalid JavaScript.
**How to identify**: Syntax error or "Cannot read property '0' of undefined"
---
## 8. Using Expressions in Code Nodes
**Problem**: Literal string instead of value, or errors
❌ **Wrong (in Code node)**:
```javascript
const email = '{{$json.email}}';
const name = '={{$json.body.name}}';
```
✅ **Correct (in Code node)**:
```javascript
const email = $json.email;
const name = $json.body.name;
// Or using Code node API
const email = $input.item.json.email;
const allItems = $input.all();
```
**Why it fails**: Code nodes have **direct access** to data. The {{ }} syntax is for expression fields in other nodes, not for JavaScript code.
**How to identify**: Literal string "{{$json.email}}" appears in Code node output instead of actual value.
---
## 9. Missing Quotes in $node Reference
**Problem**: Syntax error
❌ **Wrong**:
```
{{$node[HTTP Request].json.data}}
```
✅ **Correct**:
```
{{$node["HTTP Request"].json.data}}
```
**Why it fails**: Node names must be quoted strings inside brackets.
**How to identify**: Syntax error "Unexpected identifier"
---
## 10. Incorrect Property Path
**Problem**: Undefined value
❌ **Wrong**:
```
{{$json.data.items.name}} // items is an array
{{$json.user.email}} // user doesn't exist, it's userData
```
✅ **Correct**:
```
{{$json.data.items[0].name}} // access array element
{{$json.userData.email}} // correct property name
```
**Why it fails**: Wrong path to data. Arrays need index, property names must be exact.
**How to identify**: Check actual data structure using expression editor preview.
---
## 11. Using = Prefix Outside JSON
**Problem**: Literal "=" appears in output
❌ **Wrong (in text field)**:
```
Email: ={{$json.email}}
```
✅ **Correct (in text field)**:
```
Email: {{$json.email}}
```
**Note**: The `=` prefix is **only** needed in JSON mode or when you want to set entire field value to expression result:
```javascript
// JSON mode (set property to expression)
{
"email": "={{$json.body.email}}"
}
// Text mode (no = needed)
Hello {{$json.body.name}}!
```
**Why it fails**: The `=` is parsed as literal text in non-JSON contexts.
**How to identify**: Output shows "=john@example.com" instead of "john@example.com"
---
## 12. Expressions in Webhook Path
**Problem**: Path doesn't update, validation error
❌ **Wrong**:
```
path: "{{$json.user_id}}/webhook"
path: "users/={{$env.TENANT_ID}}"
```
✅ **Correct**:
```
path: "my-webhook" // Static paths only
path: "user-webhook/:userId" // Use dynamic URL parameters instead
```
**Why it fails**: Webhook paths must be static. Use dynamic URL parameters (`:paramName`) instead of expressions.
**How to identify**: Webhook path doesn't change or validation warns about invalid path.
---
## 13. Forgetting .json in $node Reference
**Problem**: Undefined or wrong data
❌ **Wrong**:
```
{{$node["HTTP Request"].data}} // Missing .json
{{$node["Webhook"].body.email}} // Missing .json
```
✅ **Correct**:
```
{{$node["HTTP Request"].json.data}}
{{$node["Webhook"].json.body.email}}
```
**Why it fails**: Node data is always under `.json` property (or `.binary` for binary data).
**How to identify**: Undefined value when you know the node has data.
---
## 14. String Concatenation Confusion
**Problem**: Attempting JavaScript template literals
❌ **Wrong**:
```
`Hello ${$json.name}!` // Template literal syntax
"Hello " + $json.name + "!" // String concatenation
```
✅ **Correct**:
```
Hello {{$json.name}}! // n8n expressions auto-concatenate
```
**Why it fails**: n8n expressions don't use JavaScript template literal syntax. Adjacent text and expressions are automatically concatenated.
**How to identify**: Literal backticks or + symbols appear in output.
---
## 15. Empty Expression Brackets
**Problem**: Literal {{}} in output
❌ **Wrong**:
```
{{}}
{{ }}
```
✅ **Correct**:
```
{{$json.field}} // Include expression content
```
**Why it fails**: Empty expression brackets have nothing to evaluate.
**How to identify**: Literal "{{ }}" text appears in output.
---
## Quick Reference Table
| Error | Symptom | Fix |
|-------|---------|-----|
| No {{ }} | Literal text | Add {{ }} |
| Webhook data | Undefined | Add `.body` |
| Space in field | Syntax error | Use `['field name']` |
| Space in node | Undefined | Use `["Node Name"]` |
| Wrong case | Undefined | Match exact case |
| Double {{ }} | Literal braces | Remove extra {{ }} |
| .0 array | Syntax error | Use [0] |
| {{ }} in Code | Literal string | Remove {{ }} |
| No quotes in $node | Syntax error | Add quotes |
| Wrong path | Undefined | Check data structure |
| = in text | Literal = | Remove = prefix |
| Dynamic path | Doesn't work | Use static path |
| Missing .json | Undefined | Add .json |
| Template literals | Literal text | Use {{ }} |
| Empty {{ }} | Literal braces | Add expression |
---
## Debugging Process
When expression doesn't work:
1. **Check braces**: Is it wrapped in {{ }}?
2. **Check data source**: Is it webhook data? Add `.body`
3. **Check spaces**: Field or node name has spaces? Use brackets
4. **Check case**: Does node name match exactly?
5. **Check path**: Is the property path correct?
6. **Use expression editor**: Preview shows actual result
7. **Check context**: Is it a Code node? Remove {{ }}
---
**Related**: See [EXAMPLES.md](EXAMPLES.md) for working examples of correct syntax.

View File

@@ -0,0 +1,483 @@
# n8n Expression Examples
Real working examples from n8n workflows.
---
## Example 1: Webhook Form Submission
**Scenario**: Form submission webhook posts to Slack
**Workflow**: Webhook → Slack
**Webhook Input** (POST):
```json
{
"name": "John Doe",
"email": "john@example.com",
"company": "Acme Corp",
"message": "Interested in your product"
}
```
**Webhook Node Output**:
```json
{
"headers": {"content-type": "application/json"},
"params": {},
"query": {},
"body": {
"name": "John Doe",
"email": "john@example.com",
"company": "Acme Corp",
"message": "Interested in your product"
}
}
```
**In Slack Node** (text field):
```
New form submission! 📝
Name: {{$json.body.name}}
Email: {{$json.body.email}}
Company: {{$json.body.company}}
Message: {{$json.body.message}}
```
**Output**:
```
New form submission! 📝
Name: John Doe
Email: john@example.com
Company: Acme Corp
Message: Interested in your product
```
---
## Example 2: HTTP API to Database
**Scenario**: Fetch user data from API and insert into database
**Workflow**: Schedule → HTTP Request → Postgres
**HTTP Request Returns**:
```json
{
"data": {
"users": [
{
"id": 123,
"name": "Alice Smith",
"email": "alice@example.com",
"role": "admin"
}
]
}
}
```
**In Postgres Node** (INSERT statement):
```sql
INSERT INTO users (user_id, name, email, role, synced_at)
VALUES (
{{$json.data.users[0].id}},
'{{$json.data.users[0].name}}',
'{{$json.data.users[0].email}}',
'{{$json.data.users[0].role}}',
'{{$now.toFormat('yyyy-MM-dd HH:mm:ss')}}'
)
```
**Result**: User inserted with current timestamp
---
## Example 3: Multi-Node Data Flow
**Scenario**: Webhook → HTTP Request → Email
**Workflow Structure**:
1. Webhook receives order ID
2. HTTP Request fetches order details
3. Email sends confirmation
### Node 1: Webhook
**Receives**:
```json
{
"body": {
"order_id": "ORD-12345"
}
}
```
### Node 2: HTTP Request
**URL field**:
```
https://api.example.com/orders/{{$json.body.order_id}}
```
**Returns**:
```json
{
"order": {
"id": "ORD-12345",
"customer": "Bob Jones",
"total": 99.99,
"items": ["Widget", "Gadget"]
}
}
```
### Node 3: Email
**Subject**:
```
Order {{$node["Webhook"].json.body.order_id}} Confirmed
```
**Body**:
```
Dear {{$node["HTTP Request"].json.order.customer}},
Your order {{$node["Webhook"].json.body.order_id}} has been confirmed!
Total: ${{$node["HTTP Request"].json.order.total}}
Items: {{$node["HTTP Request"].json.order.items.join(', ')}}
Thank you for your purchase!
```
**Email Result**:
```
Subject: Order ORD-12345 Confirmed
Dear Bob Jones,
Your order ORD-12345 has been confirmed!
Total: $99.99
Items: Widget, Gadget
Thank you for your purchase!
```
---
## Example 4: Date Formatting
**Scenario**: Various date format outputs
**Current Time**: 2025-10-20 14:30:45
### ISO Format
```javascript
{{$now.toISO()}}
```
**Output**: `2025-10-20T14:30:45.000Z`
### Custom Date Format
```javascript
{{$now.toFormat('yyyy-MM-dd')}}
```
**Output**: `2025-10-20`
### Time Only
```javascript
{{$now.toFormat('HH:mm:ss')}}
```
**Output**: `14:30:45`
### Full Readable Format
```javascript
{{$now.toFormat('MMMM dd, yyyy')}}
```
**Output**: `October 20, 2025`
### Date Math - Future
```javascript
{{$now.plus({days: 7}).toFormat('yyyy-MM-dd')}}
```
**Output**: `2025-10-27`
### Date Math - Past
```javascript
{{$now.minus({hours: 24}).toFormat('yyyy-MM-dd HH:mm')}}
```
**Output**: `2025-10-19 14:30`
---
## Example 5: Array Operations
**Data**:
```json
{
"users": [
{"name": "Alice", "email": "alice@example.com"},
{"name": "Bob", "email": "bob@example.com"},
{"name": "Charlie", "email": "charlie@example.com"}
]
}
```
### First User
```javascript
{{$json.users[0].name}}
```
**Output**: `Alice`
### Last User
```javascript
{{$json.users[$json.users.length - 1].name}}
```
**Output**: `Charlie`
### All Emails (Join)
```javascript
{{$json.users.map(u => u.email).join(', ')}}
```
**Output**: `alice@example.com, bob@example.com, charlie@example.com`
### Array Length
```javascript
{{$json.users.length}}
```
**Output**: `3`
---
## Example 6: Conditional Logic
**Data**:
```json
{
"order": {
"status": "completed",
"total": 150
}
}
```
### Ternary Operator
```javascript
{{$json.order.status === 'completed' ? 'Order Complete ✓' : 'Pending...'}}
```
**Output**: `Order Complete ✓`
### Default Values
```javascript
{{$json.order.notes || 'No notes provided'}}
```
**Output**: `No notes provided` (if notes field doesn't exist)
### Multiple Conditions
```javascript
{{$json.order.total > 100 ? 'Premium Customer' : 'Standard Customer'}}
```
**Output**: `Premium Customer`
---
## Example 7: String Manipulation
**Data**:
```json
{
"user": {
"email": "JOHN@EXAMPLE.COM",
"message": " Hello World "
}
}
```
### Lowercase
```javascript
{{$json.user.email.toLowerCase()}}
```
**Output**: `john@example.com`
### Uppercase
```javascript
{{$json.user.message.toUpperCase()}}
```
**Output**: ` HELLO WORLD `
### Trim
```javascript
{{$json.user.message.trim()}}
```
**Output**: `Hello World`
### Substring
```javascript
{{$json.user.email.substring(0, 4)}}
```
**Output**: `JOHN`
### Replace
```javascript
{{$json.user.message.replace('World', 'n8n')}}
```
**Output**: ` Hello n8n `
---
## Example 8: Fields with Spaces
**Data**:
```json
{
"user data": {
"first name": "Jane",
"last name": "Doe",
"phone number": "+1234567890"
}
}
```
### Bracket Notation
```javascript
{{$json['user data']['first name']}}
```
**Output**: `Jane`
### Combined
```javascript
{{$json['user data']['first name']}} {{$json['user data']['last name']}}
```
**Output**: `Jane Doe`
### Nested Spaces
```javascript
Contact: {{$json['user data']['phone number']}}
```
**Output**: `Contact: +1234567890`
---
## Example 9: Code Node (Direct Access)
**Code Node**: Transform webhook data
**Input** (from Webhook node):
```json
{
"body": {
"items": ["apple", "banana", "cherry"]
}
}
```
**Code** (JavaScript):
```javascript
// ✅ Direct access (no {{ }})
const items = $json.body.items;
// Transform to uppercase
const uppercased = items.map(item => item.toUpperCase());
// Return in n8n format
return [{
json: {
original: items,
transformed: uppercased,
count: items.length
}
}];
```
**Output**:
```json
{
"original": ["apple", "banana", "cherry"],
"transformed": ["APPLE", "BANANA", "CHERRY"],
"count": 3
}
```
---
## Example 10: Environment Variables
**Setup**: Environment variable `API_KEY=secret123`
### In HTTP Request (Headers)
```javascript
Authorization: Bearer {{$env.API_KEY}}
```
**Result**: `Authorization: Bearer secret123`
### In URL
```javascript
https://api.example.com/data?key={{$env.API_KEY}}
```
**Result**: `https://api.example.com/data?key=secret123`
---
## Template from Real Workflow
**Based on n8n template #2947** (Weather to Slack)
### Workflow Structure
Webhook → OpenStreetMap API → Weather API → Slack
### Webhook Slash Command
**Input**: `/weather London`
**Webhook receives**:
```json
{
"body": {
"text": "London"
}
}
```
### OpenStreetMap API
**URL**:
```
https://nominatim.openstreetmap.org/search?q={{$json.body.text}}&format=json
```
### Weather API (NWS)
**URL**:
```
https://api.weather.gov/points/{{$node["OpenStreetMap"].json[0].lat}},{{$node["OpenStreetMap"].json[0].lon}}
```
### Slack Message
```
Weather for {{$json.body.text}}:
Temperature: {{$node["Weather API"].json.properties.temperature.value}}°C
Conditions: {{$node["Weather API"].json.properties.shortForecast}}
```
---
## Summary
**Key Patterns**:
1. Webhook data is under `.body`
2. Use `{{}}` for expressions (except Code nodes)
3. Reference other nodes with `$node["Node Name"].json`
4. Use brackets for field names with spaces
5. Node names are case-sensitive
**Most Common Uses**:
- `{{$json.body.field}}` - Webhook data
- `{{$node["Name"].json.field}}` - Other node data
- `{{$now.toFormat('yyyy-MM-dd')}}` - Timestamps
- `{{$json.array[0].field}}` - Array access
- `{{$json.field || 'default'}}` - Default values
---
**Related**: See [COMMON_MISTAKES.md](COMMON_MISTAKES.md) for error examples and fixes.

View File

@@ -0,0 +1,93 @@
# n8n Expression Syntax
Expert guide for writing correct n8n expressions in workflows.
---
## Purpose
Teaches correct n8n expression syntax ({{ }} patterns) and fixes common mistakes, especially the critical webhook data structure gotcha.
## Activates On
- expression
- {{}} syntax
- $json, $node, $now, $env
- webhook data
- troubleshoot expression error
- undefined in workflow
## File Count
4 files, ~450 lines total
## Dependencies
**n8n-mcp tools**:
- None directly (syntax knowledge skill)
- Works with n8n-mcp validation tools
**Related skills**:
- n8n Workflow Patterns (uses expressions in examples)
- n8n MCP Tools Expert (validates expressions)
- n8n Node Configuration (when expressions are needed)
## Coverage
### Core Topics
- Expression format ({{ }})
- Core variables ($json, $node, $now, $env)
- **Webhook data structure** ($json.body.*)
- When NOT to use expressions (Code nodes)
### Common Patterns
- Accessing nested fields
- Referencing other nodes
- Array and object access
- Date/time formatting
- String manipulation
### Error Prevention
- 15 common mistakes with fixes
- Quick reference table
- Debugging process
## Evaluations
4 scenarios (100% coverage expected):
1. **eval-001**: Missing curly braces
2. **eval-002**: Webhook body data access (critical!)
3. **eval-003**: Code node vs expression confusion
4. **eval-004**: Node reference syntax
## Key Features
✅ **Critical Gotcha Highlighted**: Webhook data under `.body`
✅ **Real Examples**: From MCP testing and real templates
✅ **Quick Fixes Table**: Fast reference for common errors
✅ **Code vs Expression**: Clear distinction
✅ **Comprehensive**: Covers 95% of expression use cases
## Files
- **SKILL.md** (285 lines) - Main content with all essential knowledge
- **COMMON_MISTAKES.md** (380 lines) - Complete error catalog with 15 common mistakes
- **EXAMPLES.md** (450 lines) - 10 real working examples
- **README.md** (this file) - Skill metadata
## Success Metrics
**Expected outcomes**:
- Users correctly wrap expressions in {{ }}
- Zero webhook `.body` access errors
- No expressions used in Code nodes
- Correct $node reference syntax
## Last Updated
2025-10-20
---
**Part of**: n8n-skills repository
**Conceived by**: Romuald Członkowski - [www.aiadvisors.pl/en](https://www.aiadvisors.pl/en)

View File

@@ -0,0 +1,560 @@
---
name: n8n-expression-syntax
description: Validate n8n expression syntax and fix common errors. Use when writing n8n expressions, using {{}} syntax, accessing $json/$node variables, troubleshooting expression errors, or working with webhook data in workflows.
---
# n8n Expression Syntax
Expert guide for writing correct n8n expressions in workflows.
---
## Expression Format
All dynamic content in n8n uses **double curly braces**:
```
{{expression}}
```
**Examples**:
```
✅ {{$json.email}}
✅ {{$json.body.name}}
✅ {{$node["HTTP Request"].json.data}}
❌ $json.email (no braces - treated as literal text)
❌ {$json.email} (single braces - invalid)
```
---
## Core Variables
### $json - Current Node Output
Access data from the current node:
```javascript
{{$json.fieldName}}
{{$json['field with spaces']}}
{{$json.nested.property}}
{{$json.items[0].name}}
```
### $node - Reference Other Nodes
Access data from any previous node:
```javascript
{{$node["Node Name"].json.fieldName}}
{{$node["HTTP Request"].json.data}}
{{$node["Webhook"].json.body.email}}
```
**Important**:
- Node names **must** be in quotes
- Node names are **case-sensitive**
- Must match exact node name from workflow
### $now - Current Timestamp
Access current date/time:
```javascript
{{$now}}
{{$now.toFormat('yyyy-MM-dd')}}
{{$now.toFormat('HH:mm:ss')}}
{{$now.plus({days: 7})}}
```
### $env - Environment Variables
Access environment variables:
```javascript
{{$env.API_KEY}}
{{$env.DATABASE_URL}}
```
---
## 🚨 CRITICAL: Webhook Data Structure
**Most Common Mistake**: Webhook data is **NOT** at the root!
### Webhook Node Output Structure
```javascript
{
"headers": {...},
"params": {...},
"query": {...},
"body": { // ⚠️ USER DATA IS HERE!
"name": "John",
"email": "john@example.com",
"message": "Hello"
}
}
```
### Correct Webhook Data Access
```javascript
❌ WRONG: {{$json.name}}
❌ WRONG: {{$json.email}}
✅ CORRECT: {{$json.body.name}}
✅ CORRECT: {{$json.body.email}}
✅ CORRECT: {{$json.body.message}}
```
**Why**: Webhook node wraps incoming data under `.body` property to preserve headers, params, and query parameters.
---
## Common Patterns
### Access Nested Fields
```javascript
// Simple nesting
{{$json.user.email}}
// Array access
{{$json.data[0].name}}
{{$json.items[0].id}}
// Bracket notation for spaces
{{$json['field name']}}
{{$json['user data']['first name']}}
```
### Reference Other Nodes
```javascript
// Node without spaces
{{$node["Set"].json.value}}
// Node with spaces (common!)
{{$node["HTTP Request"].json.data}}
{{$node["Respond to Webhook"].json.message}}
// Webhook node
{{$node["Webhook"].json.body.email}}
```
### Combine Variables
```javascript
// Concatenation (automatic)
Hello {{$json.body.name}}!
// In URLs
https://api.example.com/users/{{$json.body.user_id}}
// In object properties
{
"name": "={{$json.body.name}}",
"email": "={{$json.body.email}}"
}
```
---
## When NOT to Use Expressions
### ❌ Code Nodes
Code nodes use **direct JavaScript access**, NOT expressions!
```javascript
// ❌ WRONG in Code node
const email = '={{$json.email}}';
const name = '{{$json.body.name}}';
// ✅ CORRECT in Code node
const email = $json.email;
const name = $json.body.name;
// Or using Code node API
const email = $input.item.json.email;
const allItems = $input.all();
```
### ❌ Webhook Paths
```javascript
// ❌ WRONG
path: "{{$json.user_id}}/webhook"
// ✅ CORRECT
path: "user-webhook" // Static paths only
```
### ❌ Credential Fields
```javascript
// ❌ WRONG
apiKey: "={{$env.API_KEY}}"
// ✅ CORRECT
Use n8n credential system, not expressions
```
---
## Validation Rules
### 1. Always Use {{}}
Expressions **must** be wrapped in double curly braces.
```javascript
❌ $json.field
✅ {{$json.field}}
```
### 2. Use Quotes for Spaces
Field or node names with spaces require **bracket notation**:
```javascript
❌ {{$json.field name}}
✅ {{$json['field name']}}
❌ {{$node.HTTP Request.json}}
✅ {{$node["HTTP Request"].json}}
```
### 3. Match Exact Node Names
Node references are **case-sensitive**:
```javascript
❌ {{$node["http request"].json}} // lowercase
❌ {{$node["Http Request"].json}} // wrong case
✅ {{$node["HTTP Request"].json}} // exact match
```
### 4. No Nested {{}}
Don't double-wrap expressions:
```javascript
❌ {{{$json.field}}}
✅ {{$json.field}}
```
---
## Common Mistakes
Complete catalog of expression errors with explanations and fixes.
### Quick Fixes
| Mistake | Fix |
|---------|-----|
| `$json.field` | `{{$json.field}}` |
| `{{$json.field name}}` | `{{$json['field name']}}` |
| `{{$node.HTTP Request}}` | `{{$node["HTTP Request"]}}` |
| `{{{$json.field}}}` | `{{$json.field}}` |
| `{{$json.name}}` (webhook) | `{{$json.body.name}}` |
| `'={{$json.email}}'` (Code node) | `$json.email` |
### Complete List of Common Mistakes
1. **Missing Curly Braces** - Expressions must be wrapped in {{ }}
```javascript
❌ $json.field
✅ {{$json.field}}
```
2. **Webhook Data Path Error** - Webhook data is under .body
```javascript
❌ {{$json.name}}
✅ {{$json.body.name}}
```
3. **Node Names with Spaces** - Must use bracket notation
```javascript
❌ {{$node.HTTP Request.json.field}}
✅ {{$node["HTTP Request"].json.field}}
```
4. **Double Wrapping Expressions** - Don't nest braces
```javascript
❌ {{{$json.field}}}
✅ {{$json.field}}
```
5. **Case Sensitivity** - Node names are case-sensitive
```javascript
❌ {{$node["http request"].json}}
✅ {{$node["HTTP Request"].json}}
```
6. **Using Expressions in Code Nodes** - Code nodes use direct JavaScript
```javascript
❌ const email = '={{$json.email}}';
✅ const email = $json.email;
```
7. **Missing Quotes for Special Characters** - Fields with spaces need brackets
```javascript
❌ {{$json.field name}}
✅ {{$json['field name']}}
```
---
## Working Examples
For real workflow examples, see [EXAMPLES.md](EXAMPLES.md)
### Example 1: Webhook to Slack
**Webhook receives**:
```json
{
"body": {
"name": "John Doe",
"email": "john@example.com",
"message": "Hello!"
}
}
```
**In Slack node text field**:
```
New form submission!
Name: {{$json.body.name}}
Email: {{$json.body.email}}
Message: {{$json.body.message}}
```
### Example 2: HTTP Request to Email
**HTTP Request returns**:
```json
{
"data": {
"items": [
{"name": "Product 1", "price": 29.99}
]
}
}
```
**In Email node** (reference HTTP Request):
```
Product: {{$node["HTTP Request"].json.data.items[0].name}}
Price: ${{$node["HTTP Request"].json.data.items[0].price}}
```
### Example 3: Format Timestamp
```javascript
// Current date
{{$now.toFormat('yyyy-MM-dd')}}
// Result: 2025-10-20
// Time
{{$now.toFormat('HH:mm:ss')}}
// Result: 14:30:45
// Full datetime
{{$now.toFormat('yyyy-MM-dd HH:mm')}}
// Result: 2025-10-20 14:30
```
---
## Data Type Handling
### Arrays
```javascript
// First item
{{$json.users[0].email}}
// Array length
{{$json.users.length}}
// Last item
{{$json.users[$json.users.length - 1].name}}
```
### Objects
```javascript
// Dot notation (no spaces)
{{$json.user.email}}
// Bracket notation (with spaces or dynamic)
{{$json['user data'].email}}
```
### Strings
```javascript
// Concatenation (automatic)
Hello {{$json.name}}!
// String methods
{{$json.email.toLowerCase()}}
{{$json.name.toUpperCase()}}
```
### Numbers
```javascript
// Direct use
{{$json.price}}
// Math operations
{{$json.price * 1.1}} // Add 10%
{{$json.quantity + 5}}
```
---
## Advanced Patterns
### Conditional Content
```javascript
// Ternary operator
{{$json.status === 'active' ? 'Active User' : 'Inactive User'}}
// Default values
{{$json.email || 'no-email@example.com'}}
```
### Date Manipulation
```javascript
// Add days
{{$now.plus({days: 7}).toFormat('yyyy-MM-dd')}}
// Subtract hours
{{$now.minus({hours: 24}).toISO()}}
// Set specific date
{{DateTime.fromISO('2025-12-25').toFormat('MMMM dd, yyyy')}}
```
### String Manipulation
```javascript
// Substring
{{$json.email.substring(0, 5)}}
// Replace
{{$json.message.replace('old', 'new')}}
// Split and join
{{$json.tags.split(',').join(', ')}}
```
---
## Debugging Expressions
### Test in Expression Editor
1. Click field with expression
2. Open expression editor (click "fx" icon)
3. See live preview of result
4. Check for errors highlighted in red
### Common Error Messages
**"Cannot read property 'X' of undefined"**
→ Parent object doesn't exist
→ Check your data path
**"X is not a function"**
→ Trying to call method on non-function
→ Check variable type
**Expression shows as literal text**
→ Missing {{ }}
→ Add curly braces
---
## Expression Helpers
### Available Methods
**String**:
- `.toLowerCase()`, `.toUpperCase()`
- `.trim()`, `.replace()`, `.substring()`
- `.split()`, `.includes()`
**Array**:
- `.length`, `.map()`, `.filter()`
- `.find()`, `.join()`, `.slice()`
**DateTime** (Luxon):
- `.toFormat()`, `.toISO()`, `.toLocal()`
- `.plus()`, `.minus()`, `.set()`
**Number**:
- `.toFixed()`, `.toString()`
- Math operations: `+`, `-`, `*`, `/`, `%`
---
## Best Practices
### ✅ Do
- Always use {{ }} for dynamic content
- Use bracket notation for field names with spaces
- Reference webhook data from `.body`
- Use $node for data from other nodes
- Test expressions in expression editor
### ❌ Don't
- Don't use expressions in Code nodes
- Don't forget quotes around node names with spaces
- Don't double-wrap with extra {{ }}
- Don't assume webhook data is at root (it's under .body!)
- Don't use expressions in webhook paths or credentials
---
## Related Skills
- **n8n MCP Tools Expert**: Learn how to validate expressions using MCP tools
- **n8n Workflow Patterns**: See expressions in real workflow examples
- **n8n Node Configuration**: Understand when expressions are needed
---
## Summary
**Essential Rules**:
1. Wrap expressions in {{ }}
2. Webhook data is under `.body`
3. No {{ }} in Code nodes
4. Quote node names with spaces
5. Node names are case-sensitive
**Most Common Mistakes**:
- Missing {{ }} → Add braces
- `{{$json.name}}` in webhooks → Use `{{$json.body.name}}`
- `{{$json.email}}` in Code → Use `$json.email`
- `{{$node.HTTP Request}}` → Use `{{$node["HTTP Request"]}}`
For more details, see:
- [COMMON_MISTAKES.md](COMMON_MISTAKES.md) - Complete error catalog
- [EXAMPLES.md](EXAMPLES.md) - Real workflow examples
---
**Need Help?** Reference the n8n expression documentation or use n8n-mcp validation tools to check your expressions.

View File

@@ -0,0 +1,99 @@
# n8n MCP Tools Expert
Expert guide for using n8n-mcp MCP tools effectively.
---
## Purpose
Teaches how to use n8n-mcp MCP server tools correctly for efficient workflow building.
## Activates On
- search nodes
- find node
- validate
- MCP tools
- template
- workflow
- n8n-mcp
- tool selection
## File Count
5 files, ~1,150 lines total
## Priority
**HIGHEST** - Essential for correct MCP tool usage
## Dependencies
**n8n-mcp tools**: All of them! (40+ tools)
**Related skills**:
- n8n Expression Syntax (write expressions for workflows)
- n8n Workflow Patterns (use tools to build patterns)
- n8n Validation Expert (interpret validation results)
- n8n Node Configuration (configure nodes found with tools)
## Coverage
### Core Topics
- Tool selection guide (which tool for which task)
- nodeType format differences (nodes-base.* vs n8n-nodes-base.*)
- Validation profiles (minimal/runtime/ai-friendly/strict)
- Smart parameters (branch, case for multi-output nodes)
- Auto-sanitization system
- Workflow management (15 operation types)
- AI connection types (8 types)
### Tool Categories
- Node Discovery (search, list, essentials, info)
- Configuration Validation (minimal, operation, workflow)
- Workflow Management (create, update, validate)
- Template Library (search, get)
- Documentation (tools, database stats)
## Evaluations
5 scenarios (100% coverage expected):
1. **eval-001**: Tool selection (search_nodes)
2. **eval-002**: nodeType format (nodes-base.* prefix)
3. **eval-003**: Validation workflow (profiles)
4. **eval-004**: essentials vs info (5KB vs 100KB)
5. **eval-005**: Smart parameters (branch, case)
## Key Features
✅ **Tool Selection Guide**: Which tool to use for each task
✅ **Common Patterns**: Most effective tool usage sequences
✅ **Format Guidance**: nodeType format differences explained
✅ **Smart Parameters**: Semantic branch/case routing for multi-output nodes
✅ **Auto-Sanitization**: Explains automatic validation fixes
✅ **Comprehensive**: Covers all 40+ MCP tools
## Files
- **SKILL.md** (480 lines) - Core tool usage guide
- **SEARCH_GUIDE.md** (220 lines) - Node discovery tools
- **VALIDATION_GUIDE.md** (250 lines) - Validation tools and profiles
- **WORKFLOW_GUIDE.md** (200 lines) - Workflow management
- **README.md** (this file) - Skill metadata
## What You'll Learn
- Correct nodeType formats (nodes-base.* for search tools)
- When to use get_node_essentials vs get_node_info
- How to use validation profiles effectively
- Smart parameters for multi-output nodes (IF/Switch)
- Common tool usage patterns and workflows
## Last Updated
2025-10-20
---
**Part of**: n8n-skills repository
**Conceived by**: Romuald Członkowski - [www.aiadvisors.pl/en](https://www.aiadvisors.pl/en)

View File

@@ -0,0 +1,374 @@
# Node Discovery Tools Guide
Complete guide for finding and understanding n8n nodes.
---
## search_nodes (START HERE!)
**Speed**: <20ms
**Use when**: You know what you're looking for (keyword, service, use case)
**Syntax**:
```javascript
search_nodes({
query: "slack", // Required: search keywords
mode: "OR", // Optional: OR (default), AND, FUZZY
limit: 20, // Optional: max results (default 20)
source: "all", // Optional: all, core, community, verified
includeExamples: false // Optional: include template configs
})
```
**Returns**:
```javascript
{
"query": "slack",
"results": [
{
"nodeType": "nodes-base.slack", // For search/validate tools
"workflowNodeType": "n8n-nodes-base.slack", // For workflow tools
"displayName": "Slack",
"description": "Consume Slack API",
"category": "output",
"relevance": "high"
}
]
}
```
**Tips**:
- Common searches: webhook, http, database, email, slack, google, ai
- `OR` mode (default): matches any word
- `AND` mode: requires all words
- `FUZZY` mode: typo-tolerant (finds "slak" → Slack)
- Use `source: "core"` for only built-in nodes
- Use `includeExamples: true` for real-world configs
---
## get_node (UNIFIED NODE INFORMATION)
The `get_node` tool provides all node information with different detail levels and modes.
### Detail Levels (mode="info")
| Detail | Tokens | Use When |
|--------|--------|----------|
| `minimal` | ~200 | Quick metadata check |
| `standard` | ~1-2K | **Most use cases (DEFAULT)** |
| `full` | ~3-8K | Complex debugging only |
### Standard Detail (RECOMMENDED)
**Speed**: <10ms | **Size**: ~1-2K tokens
**Use when**: You've found the node and need configuration details
```javascript
get_node({
nodeType: "nodes-base.slack", // Required: SHORT prefix format
includeExamples: true // Optional: get real template configs
})
// detail="standard" is the default
```
**Returns**:
- Available operations and resources
- Essential properties (10-20 most common)
- Metadata (isAITool, isTrigger, hasCredentials)
- Real examples from templates (if includeExamples: true)
### Minimal Detail
**Speed**: <5ms | **Size**: ~200 tokens
**Use when**: Just need basic metadata
```javascript
get_node({
nodeType: "nodes-base.slack",
detail: "minimal"
})
```
**Returns**: nodeType, displayName, description, category
### Full Detail (USE SPARINGLY)
**Speed**: <100ms | **Size**: ~3-8K tokens
**Use when**: Debugging complex configuration, need complete schema
```javascript
get_node({
nodeType: "nodes-base.httpRequest",
detail: "full"
})
```
**Warning**: Large payload! Use `standard` for most cases.
---
## get_node Modes
### mode="docs" (READABLE DOCUMENTATION)
**Use when**: Need human-readable documentation with examples
```javascript
get_node({
nodeType: "nodes-base.slack",
mode: "docs"
})
```
**Returns**: Formatted markdown with:
- Usage examples
- Authentication guide
- Common patterns
- Best practices
**Better than raw schema for learning!**
### mode="search_properties" (FIND SPECIFIC FIELDS)
**Use when**: Looking for specific property in a node
```javascript
get_node({
nodeType: "nodes-base.httpRequest",
mode: "search_properties",
propertyQuery: "auth", // Required for this mode
maxPropertyResults: 20 // Optional: default 20
})
```
**Returns**: Property paths and descriptions matching query
**Common searches**: auth, header, body, json, url, method, credential
### mode="versions" (VERSION HISTORY)
**Use when**: Need to check node version history
```javascript
get_node({
nodeType: "nodes-base.executeWorkflow",
mode: "versions"
})
```
**Returns**: Version history with breaking changes flags
### mode="compare" (COMPARE VERSIONS)
**Use when**: Need to see differences between versions
```javascript
get_node({
nodeType: "nodes-base.httpRequest",
mode: "compare",
fromVersion: "3.0",
toVersion: "4.1" // Optional: defaults to latest
})
```
**Returns**: Property-level changes between versions
### mode="breaking" (BREAKING CHANGES ONLY)
**Use when**: Checking for breaking changes before upgrades
```javascript
get_node({
nodeType: "nodes-base.httpRequest",
mode: "breaking",
fromVersion: "3.0"
})
```
**Returns**: Only breaking changes (not all changes)
### mode="migrations" (AUTO-MIGRATABLE)
**Use when**: Checking what can be auto-migrated
```javascript
get_node({
nodeType: "nodes-base.httpRequest",
mode: "migrations",
fromVersion: "3.0"
})
```
**Returns**: Changes that can be automatically migrated
---
## Additional Parameters
### includeTypeInfo
Add type structure metadata (validation rules, JS types)
```javascript
get_node({
nodeType: "nodes-base.if",
includeTypeInfo: true // Adds ~80-120 tokens per property
})
```
Use for complex nodes like filter, resourceMapper
### includeExamples
Include real-world configuration examples from templates
```javascript
get_node({
nodeType: "nodes-base.slack",
includeExamples: true // Adds ~200-400 tokens per example
})
```
Only works with `mode: "info"` and `detail: "standard"`
---
## Common Workflow: Finding & Configuring
```
Step 1: Search
search_nodes({query: "slack"})
→ Returns: nodes-base.slack
Step 2: Get Operations (18s avg thinking time)
get_node({
nodeType: "nodes-base.slack",
includeExamples: true
})
→ Returns: operations list + example configs
Step 3: Validate Config
validate_node({
nodeType: "nodes-base.slack",
config: {resource: "channel", operation: "create"},
profile: "runtime"
})
→ Returns: validation result
Step 4: Use in Workflow
(Configuration ready!)
```
**Most common pattern**: search → get_node (18s average)
---
## Quick Comparison
| Tool/Mode | When to Use | Speed | Size |
|-----------|-------------|-------|------|
| `search_nodes` | Find by keyword | <20ms | Small |
| `get_node (standard)` | **Get config (DEFAULT)** | <10ms | 1-2K |
| `get_node (minimal)` | Quick metadata | <5ms | 200 |
| `get_node (full)` | Complex debugging | <100ms | 3-8K |
| `get_node (docs)` | Learn usage | Fast | Medium |
| `get_node (search_properties)` | Find specific field | Fast | Small |
| `get_node (versions)` | Check versions | Fast | Small |
**Best Practice**: search → get_node(standard) → validate
---
## nodeType Format (CRITICAL!)
**Search/Validate Tools** (SHORT prefix):
```javascript
"nodes-base.slack"
"nodes-base.httpRequest"
"nodes-langchain.agent"
```
**Workflow Tools** (FULL prefix):
```javascript
"n8n-nodes-base.slack"
"n8n-nodes-base.httpRequest"
"@n8n/n8n-nodes-langchain.agent"
```
**Conversion**: search_nodes returns BOTH formats:
```javascript
{
"nodeType": "nodes-base.slack", // Use with get_node, validate_node
"workflowNodeType": "n8n-nodes-base.slack" // Use with n8n_create_workflow
}
```
---
## Examples
### Find and Configure HTTP Request
```javascript
// Step 1: Search
search_nodes({query: "http request"})
// Step 2: Get standard info
get_node({nodeType: "nodes-base.httpRequest"})
// Step 3: Find auth options
get_node({
nodeType: "nodes-base.httpRequest",
mode: "search_properties",
propertyQuery: "authentication"
})
// Step 4: Validate config
validate_node({
nodeType: "nodes-base.httpRequest",
config: {method: "POST", url: "https://api.example.com"},
profile: "runtime"
})
```
### Explore AI Nodes
```javascript
// Find all AI-related nodes
search_nodes({query: "ai agent", source: "all"})
// Get AI Agent documentation
get_node({nodeType: "nodes-langchain.agent", mode: "docs"})
// Get configuration details with examples
get_node({
nodeType: "nodes-langchain.agent",
includeExamples: true
})
```
### Check Version Compatibility
```javascript
// See all versions
get_node({nodeType: "nodes-base.executeWorkflow", mode: "versions"})
// Check breaking changes from v1 to v2
get_node({
nodeType: "nodes-base.executeWorkflow",
mode: "breaking",
fromVersion: "1.0"
})
```
---
## Related
- [VALIDATION_GUIDE.md](VALIDATION_GUIDE.md) - Validate node configs
- [WORKFLOW_GUIDE.md](WORKFLOW_GUIDE.md) - Use nodes in workflows

View File

@@ -0,0 +1,642 @@
---
name: n8n-mcp-tools-expert
description: Expert guide for using n8n-mcp MCP tools effectively. Use when searching for nodes, validating configurations, accessing templates, managing workflows, or using any n8n-mcp tool. Provides tool selection guidance, parameter formats, and common patterns.
---
# n8n MCP Tools Expert
Master guide for using n8n-mcp MCP server tools to build workflows.
---
## Tool Categories
n8n-mcp provides tools organized into categories:
1. **Node Discovery** → [SEARCH_GUIDE.md](SEARCH_GUIDE.md)
2. **Configuration Validation** → [VALIDATION_GUIDE.md](VALIDATION_GUIDE.md)
3. **Workflow Management** → [WORKFLOW_GUIDE.md](WORKFLOW_GUIDE.md)
4. **Template Library** - Search and deploy 2,700+ real workflows
5. **Documentation & Guides** - Tool docs, AI agent guide, Code node guides
---
## Quick Reference
### Most Used Tools (by success rate)
| Tool | Use When | Speed |
|------|----------|-------|
| `search_nodes` | Finding nodes by keyword | <20ms |
| `get_node` | Understanding node operations (detail="standard") | <10ms |
| `validate_node` | Checking configurations (mode="full") | <100ms |
| `n8n_create_workflow` | Creating workflows | 100-500ms |
| `n8n_update_partial_workflow` | Editing workflows (MOST USED!) | 50-200ms |
| `validate_workflow` | Checking complete workflow | 100-500ms |
| `n8n_deploy_template` | Deploy template to n8n instance | 200-500ms |
---
## Tool Selection Guide
### Finding the Right Node
**Workflow**:
```
1. search_nodes({query: "keyword"})
2. get_node({nodeType: "nodes-base.name"})
3. [Optional] get_node({nodeType: "nodes-base.name", mode: "docs"})
```
**Example**:
```javascript
// Step 1: Search
search_nodes({query: "slack"})
// Returns: nodes-base.slack
// Step 2: Get details
get_node({nodeType: "nodes-base.slack"})
// Returns: operations, properties, examples (standard detail)
// Step 3: Get readable documentation
get_node({nodeType: "nodes-base.slack", mode: "docs"})
// Returns: markdown documentation
```
**Common pattern**: search → get_node (18s average)
### Validating Configuration
**Workflow**:
```
1. validate_node({nodeType, config: {}, mode: "minimal"}) - Check required fields
2. validate_node({nodeType, config, profile: "runtime"}) - Full validation
3. [Repeat] Fix errors, validate again
```
**Common pattern**: validate → fix → validate (23s thinking, 58s fixing per cycle)
### Managing Workflows
**Workflow**:
```
1. n8n_create_workflow({name, nodes, connections})
2. n8n_validate_workflow({id})
3. n8n_update_partial_workflow({id, operations: [...]})
4. n8n_validate_workflow({id}) again
5. n8n_update_partial_workflow({id, operations: [{type: "activateWorkflow"}]})
```
**Common pattern**: iterative updates (56s average between edits)
---
## Critical: nodeType Formats
**Two different formats** for different tools!
### Format 1: Search/Validate Tools
```javascript
// Use SHORT prefix
"nodes-base.slack"
"nodes-base.httpRequest"
"nodes-base.webhook"
"nodes-langchain.agent"
```
**Tools that use this**:
- search_nodes (returns this format)
- get_node
- validate_node
- validate_workflow
### Format 2: Workflow Tools
```javascript
// Use FULL prefix
"n8n-nodes-base.slack"
"n8n-nodes-base.httpRequest"
"n8n-nodes-base.webhook"
"@n8n/n8n-nodes-langchain.agent"
```
**Tools that use this**:
- n8n_create_workflow
- n8n_update_partial_workflow
### Conversion
```javascript
// search_nodes returns BOTH formats
{
"nodeType": "nodes-base.slack", // For search/validate tools
"workflowNodeType": "n8n-nodes-base.slack" // For workflow tools
}
```
---
## Common Mistakes
### Mistake 1: Wrong nodeType Format
**Problem**: "Node not found" error
```javascript
// WRONG
get_node({nodeType: "slack"}) // Missing prefix
get_node({nodeType: "n8n-nodes-base.slack"}) // Wrong prefix
// CORRECT
get_node({nodeType: "nodes-base.slack"})
```
### Mistake 2: Using detail="full" by Default
**Problem**: Huge payload, slower response, token waste
```javascript
// WRONG - Returns 3-8K tokens, use sparingly
get_node({nodeType: "nodes-base.slack", detail: "full"})
// CORRECT - Returns 1-2K tokens, covers 95% of use cases
get_node({nodeType: "nodes-base.slack"}) // detail="standard" is default
get_node({nodeType: "nodes-base.slack", detail: "standard"})
```
**When to use detail="full"**:
- Debugging complex configuration issues
- Need complete property schema with all nested options
- Exploring advanced features
**Better alternatives**:
1. `get_node({detail: "standard"})` - for operations list (default)
2. `get_node({mode: "docs"})` - for readable documentation
3. `get_node({mode: "search_properties", propertyQuery: "auth"})` - for specific property
### Mistake 3: Not Using Validation Profiles
**Problem**: Too many false positives OR missing real errors
**Profiles**:
- `minimal` - Only required fields (fast, permissive)
- `runtime` - Values + types (recommended for pre-deployment)
- `ai-friendly` - Reduce false positives (for AI configuration)
- `strict` - Maximum validation (for production)
```javascript
// WRONG - Uses default profile
validate_node({nodeType, config})
// CORRECT - Explicit profile
validate_node({nodeType, config, profile: "runtime"})
```
### Mistake 4: Ignoring Auto-Sanitization
**What happens**: ALL nodes sanitized on ANY workflow update
**Auto-fixes**:
- Binary operators (equals, contains) → removes singleValue
- Unary operators (isEmpty, isNotEmpty) → adds singleValue: true
- IF/Switch nodes → adds missing metadata
**Cannot fix**:
- Broken connections
- Branch count mismatches
- Paradoxical corrupt states
```javascript
// After ANY update, auto-sanitization runs on ALL nodes
n8n_update_partial_workflow({id, operations: [...]})
// → Automatically fixes operator structures
```
### Mistake 5: Not Using Smart Parameters
**Problem**: Complex sourceIndex calculations for multi-output nodes
**Old way** (manual):
```javascript
// IF node connection
{
type: "addConnection",
source: "IF",
target: "Handler",
sourceIndex: 0 // Which output? Hard to remember!
}
```
**New way** (smart parameters):
```javascript
// IF node - semantic branch names
{
type: "addConnection",
source: "IF",
target: "True Handler",
branch: "true" // Clear and readable!
}
{
type: "addConnection",
source: "IF",
target: "False Handler",
branch: "false"
}
// Switch node - semantic case numbers
{
type: "addConnection",
source: "Switch",
target: "Handler A",
case: 0
}
```
### Mistake 6: Not Using intent Parameter
**Problem**: Less helpful tool responses
```javascript
// WRONG - No context for response
n8n_update_partial_workflow({
id: "abc",
operations: [{type: "addNode", node: {...}}]
})
// CORRECT - Better AI responses
n8n_update_partial_workflow({
id: "abc",
intent: "Add error handling for API failures",
operations: [{type: "addNode", node: {...}}]
})
```
---
## Tool Usage Patterns
### Pattern 1: Node Discovery (Most Common)
**Common workflow**: 18s average between steps
```javascript
// Step 1: Search (fast!)
const results = await search_nodes({
query: "slack",
mode: "OR", // Default: any word matches
limit: 20
});
// → Returns: nodes-base.slack, nodes-base.slackTrigger
// Step 2: Get details (~18s later, user reviewing results)
const details = await get_node({
nodeType: "nodes-base.slack",
includeExamples: true // Get real template configs
});
// → Returns: operations, properties, metadata
```
### Pattern 2: Validation Loop
**Typical cycle**: 23s thinking, 58s fixing
```javascript
// Step 1: Validate
const result = await validate_node({
nodeType: "nodes-base.slack",
config: {
resource: "channel",
operation: "create"
},
profile: "runtime"
});
// Step 2: Check errors (~23s thinking)
if (!result.valid) {
console.log(result.errors); // "Missing required field: name"
}
// Step 3: Fix config (~58s fixing)
config.name = "general";
// Step 4: Validate again
await validate_node({...}); // Repeat until clean
```
### Pattern 3: Workflow Editing
**Most used update tool**: 99.0% success rate, 56s average between edits
```javascript
// Iterative workflow building (NOT one-shot!)
// Edit 1
await n8n_update_partial_workflow({
id: "workflow-id",
intent: "Add webhook trigger",
operations: [{type: "addNode", node: {...}}]
});
// ~56s later...
// Edit 2
await n8n_update_partial_workflow({
id: "workflow-id",
intent: "Connect webhook to processor",
operations: [{type: "addConnection", source: "...", target: "..."}]
});
// ~56s later...
// Edit 3 (validation)
await n8n_validate_workflow({id: "workflow-id"});
// Ready? Activate!
await n8n_update_partial_workflow({
id: "workflow-id",
intent: "Activate workflow for production",
operations: [{type: "activateWorkflow"}]
});
```
---
## Detailed Guides
### Node Discovery Tools
See [SEARCH_GUIDE.md](SEARCH_GUIDE.md) for:
- search_nodes
- get_node with detail levels (minimal, standard, full)
- get_node modes (info, docs, search_properties, versions)
### Validation Tools
See [VALIDATION_GUIDE.md](VALIDATION_GUIDE.md) for:
- Validation profiles explained
- validate_node with modes (minimal, full)
- validate_workflow complete structure
- Auto-sanitization system
- Handling validation errors
### Workflow Management
See [WORKFLOW_GUIDE.md](WORKFLOW_GUIDE.md) for:
- n8n_create_workflow
- n8n_update_partial_workflow (17 operation types!)
- Smart parameters (branch, case)
- AI connection types (8 types)
- Workflow activation (activateWorkflow/deactivateWorkflow)
- n8n_deploy_template
- n8n_workflow_versions
---
## Template Usage
### Search Templates
```javascript
// Search by keyword (default mode)
search_templates({
query: "webhook slack",
limit: 20
});
// Search by node types
search_templates({
searchMode: "by_nodes",
nodeTypes: ["n8n-nodes-base.httpRequest", "n8n-nodes-base.slack"]
});
// Search by task type
search_templates({
searchMode: "by_task",
task: "webhook_processing"
});
// Search by metadata (complexity, setup time)
search_templates({
searchMode: "by_metadata",
complexity: "simple",
maxSetupMinutes: 15
});
```
### Get Template Details
```javascript
get_template({
templateId: 2947,
mode: "structure" // nodes+connections only
});
get_template({
templateId: 2947,
mode: "full" // complete workflow JSON
});
```
### Deploy Template Directly
```javascript
// Deploy template to your n8n instance
n8n_deploy_template({
templateId: 2947,
name: "My Weather to Slack", // Custom name (optional)
autoFix: true, // Auto-fix common issues (default)
autoUpgradeVersions: true // Upgrade node versions (default)
});
// Returns: workflow ID, required credentials, fixes applied
```
---
## Self-Help Tools
### Get Tool Documentation
```javascript
// Overview of all tools
tools_documentation()
// Specific tool details
tools_documentation({
topic: "search_nodes",
depth: "full"
})
// Code node guides
tools_documentation({topic: "javascript_code_node_guide", depth: "full"})
tools_documentation({topic: "python_code_node_guide", depth: "full"})
```
### AI Agent Guide
```javascript
// Comprehensive AI workflow guide
ai_agents_guide()
// Returns: Architecture, connections, tools, validation, best practices
```
### Health Check
```javascript
// Quick health check
n8n_health_check()
// Detailed diagnostics
n8n_health_check({mode: "diagnostic"})
// → Returns: status, env vars, tool status, API connectivity
```
---
## Tool Availability
**Always Available** (no n8n API needed):
- search_nodes, get_node
- validate_node, validate_workflow
- search_templates, get_template
- tools_documentation, ai_agents_guide
**Requires n8n API** (N8N_API_URL + N8N_API_KEY):
- n8n_create_workflow
- n8n_update_partial_workflow
- n8n_validate_workflow (by ID)
- n8n_list_workflows, n8n_get_workflow
- n8n_test_workflow
- n8n_executions
- n8n_deploy_template
- n8n_workflow_versions
- n8n_autofix_workflow
If API tools unavailable, use templates and validation-only workflows.
---
## Unified Tool Reference
### get_node (Unified Node Information)
**Detail Levels** (mode="info", default):
- `minimal` (~200 tokens) - Basic metadata only
- `standard` (~1-2K tokens) - Essential properties + operations (RECOMMENDED)
- `full` (~3-8K tokens) - Complete schema (use sparingly)
**Operation Modes**:
- `info` (default) - Node schema with detail level
- `docs` - Readable markdown documentation
- `search_properties` - Find specific properties (use with propertyQuery)
- `versions` - List all versions with breaking changes
- `compare` - Compare two versions
- `breaking` - Show only breaking changes
- `migrations` - Show auto-migratable changes
```javascript
// Standard (recommended)
get_node({nodeType: "nodes-base.httpRequest"})
// Get documentation
get_node({nodeType: "nodes-base.webhook", mode: "docs"})
// Search for properties
get_node({nodeType: "nodes-base.httpRequest", mode: "search_properties", propertyQuery: "auth"})
// Check versions
get_node({nodeType: "nodes-base.executeWorkflow", mode: "versions"})
```
### validate_node (Unified Validation)
**Modes**:
- `full` (default) - Comprehensive validation with errors/warnings/suggestions
- `minimal` - Quick required fields check only
**Profiles** (for mode="full"):
- `minimal` - Very lenient
- `runtime` - Standard (default, recommended)
- `ai-friendly` - Balanced for AI workflows
- `strict` - Most thorough (production)
```javascript
// Full validation with runtime profile
validate_node({nodeType: "nodes-base.slack", config: {...}, profile: "runtime"})
// Quick required fields check
validate_node({nodeType: "nodes-base.webhook", config: {}, mode: "minimal"})
```
---
## Performance Characteristics
| Tool | Response Time | Payload Size |
|------|---------------|--------------|
| search_nodes | <20ms | Small |
| get_node (standard) | <10ms | ~1-2KB |
| get_node (full) | <100ms | 3-8KB |
| validate_node (minimal) | <50ms | Small |
| validate_node (full) | <100ms | Medium |
| validate_workflow | 100-500ms | Medium |
| n8n_create_workflow | 100-500ms | Medium |
| n8n_update_partial_workflow | 50-200ms | Small |
| n8n_deploy_template | 200-500ms | Medium |
---
## Best Practices
### Do
- Use `get_node({detail: "standard"})` for most use cases
- Specify validation profile explicitly (`profile: "runtime"`)
- Use smart parameters (`branch`, `case`) for clarity
- Include `intent` parameter in workflow updates
- Follow search → get_node → validate workflow
- Iterate workflows (avg 56s between edits)
- Validate after every significant change
- Use `includeExamples: true` for real configs
- Use `n8n_deploy_template` for quick starts
### Don't
- Use `detail: "full"` unless necessary (wastes tokens)
- Forget nodeType prefix (`nodes-base.*`)
- Skip validation profiles
- Try to build workflows in one shot (iterate!)
- Ignore auto-sanitization behavior
- Use full prefix (`n8n-nodes-base.*`) with search/validate tools
- Forget to activate workflows after building
---
## Summary
**Most Important**:
1. Use **get_node** with `detail: "standard"` (default) - covers 95% of use cases
2. nodeType formats differ: `nodes-base.*` (search/validate) vs `n8n-nodes-base.*` (workflows)
3. Specify **validation profiles** (`runtime` recommended)
4. Use **smart parameters** (`branch="true"`, `case=0`)
5. Include **intent parameter** in workflow updates
6. **Auto-sanitization** runs on ALL nodes during updates
7. Workflows can be **activated via API** (`activateWorkflow` operation)
8. Workflows are built **iteratively** (56s avg between edits)
**Common Workflow**:
1. search_nodes → find node
2. get_node → understand config
3. validate_node → check config
4. n8n_create_workflow → build
5. n8n_validate_workflow → verify
6. n8n_update_partial_workflow → iterate
7. activateWorkflow → go live!
For details, see:
- [SEARCH_GUIDE.md](SEARCH_GUIDE.md) - Node discovery
- [VALIDATION_GUIDE.md](VALIDATION_GUIDE.md) - Configuration validation
- [WORKFLOW_GUIDE.md](WORKFLOW_GUIDE.md) - Workflow management
---
**Related Skills**:
- n8n Expression Syntax - Write expressions in workflow fields
- n8n Workflow Patterns - Architectural patterns from templates
- n8n Validation Expert - Interpret validation errors
- n8n Node Configuration - Operation-specific requirements
- n8n Code JavaScript - Write JavaScript in Code nodes
- n8n Code Python - Write Python in Code nodes

View File

@@ -0,0 +1,442 @@
# Configuration Validation Tools Guide
Complete guide for validating node configurations and workflows.
---
## Validation Philosophy
**Validate early, validate often**
Validation is typically iterative with validate → fix cycles
---
## validate_node (UNIFIED VALIDATION)
The `validate_node` tool provides all validation capabilities with different modes.
### Quick Check (mode="minimal")
**Speed**: <50ms
**Use when**: Checking what fields are required
```javascript
validate_node({
nodeType: "nodes-base.slack",
config: {}, // Empty to see all required fields
mode: "minimal"
})
```
**Returns**:
```javascript
{
"valid": true, // Usually true (most nodes have no strict requirements)
"missingRequiredFields": []
}
```
**When to use**: Planning configuration, seeing basic requirements
### Full Validation (mode="full", DEFAULT)
**Speed**: <100ms
**Use when**: Validating actual configuration before deployment
```javascript
validate_node({
nodeType: "nodes-base.slack",
config: {
resource: "channel",
operation: "create",
channel: "general"
},
profile: "runtime" // Recommended!
})
// mode="full" is the default
```
---
## Validation Profiles
Choose based on your stage:
**minimal** - Only required fields
- Fastest
- Most permissive
- Use: Quick checks during editing
**runtime** - Values + types (**RECOMMENDED**)
- Balanced validation
- Catches real errors
- Use: Pre-deployment validation
**ai-friendly** - Reduce false positives
- For AI-generated configs
- Tolerates minor issues
- Use: When AI configures nodes
**strict** - Maximum validation
- Strictest rules
- May have false positives
- Use: Production deployment
---
## Validation Response
```javascript
{
"nodeType": "nodes-base.slack",
"workflowNodeType": "n8n-nodes-base.slack",
"displayName": "Slack",
"valid": false,
"errors": [
{
"type": "missing_required",
"property": "name",
"message": "Channel name is required",
"fix": "Provide a channel name (lowercase, no spaces, 1-80 characters)"
}
],
"warnings": [
{
"type": "best_practice",
"property": "errorHandling",
"message": "Slack API can have rate limits",
"suggestion": "Add onError: 'continueRegularOutput' with retryOnFail"
}
],
"suggestions": [],
"summary": {
"hasErrors": true,
"errorCount": 1,
"warningCount": 1,
"suggestionCount": 0
}
}
```
### Error Types
- `missing_required` - Must fix
- `invalid_value` - Must fix
- `type_mismatch` - Must fix
- `best_practice` - Should fix (warning)
- `suggestion` - Optional improvement
---
## validate_workflow (STRUCTURE VALIDATION)
**Speed**: 100-500ms
**Use when**: Checking complete workflow before execution
**Syntax**:
```javascript
validate_workflow({
workflow: {
nodes: [...], // Array of nodes
connections: {...} // Connections object
},
options: {
validateNodes: true, // Default: true
validateConnections: true, // Default: true
validateExpressions: true, // Default: true
profile: "runtime" // For node validation
}
})
```
**Validates**:
- Node configurations
- Connection validity (no broken references)
- Expression syntax ({{ }} patterns)
- Workflow structure (triggers, flow)
- AI connections (8 types)
**Returns**: Comprehensive validation report with errors, warnings, suggestions
### Validate by Workflow ID
```javascript
// Validate workflow already in n8n
n8n_validate_workflow({
id: "workflow-id",
options: {
validateNodes: true,
validateConnections: true,
validateExpressions: true,
profile: "runtime"
}
})
```
---
## Validation Loop Pattern
**Typical cycle**: 23s thinking, 58s fixing
```
1. Configure node
↓
2. validate_node (23s thinking about errors)
↓
3. Fix errors
↓
4. validate_node again (58s fixing)
↓
5. Repeat until valid
```
**Example**:
```javascript
// Iteration 1
let config = {
resource: "channel",
operation: "create"
};
const result1 = validate_node({
nodeType: "nodes-base.slack",
config,
profile: "runtime"
});
// → Error: Missing "name"
// Iteration 2 (~58s later)
config.name = "general";
const result2 = validate_node({
nodeType: "nodes-base.slack",
config,
profile: "runtime"
});
// → Valid!
```
---
## Auto-Sanitization System
**When it runs**: On ANY workflow update (create or update_partial)
**What it fixes** (automatically on ALL nodes):
1. Binary operators (equals, contains, greaterThan) → removes `singleValue`
2. Unary operators (isEmpty, isNotEmpty, true, false) → adds `singleValue: true`
3. Invalid operator structures → corrects to proper format
4. IF v2.2+ nodes → adds complete `conditions.options` metadata
5. Switch v3.2+ nodes → adds complete `conditions.options` for all rules
**What it CANNOT fix**:
- Broken connections (references to non-existent nodes)
- Branch count mismatches (3 Switch rules but only 2 outputs)
- Paradoxical corrupt states (API returns corrupt, rejects updates)
**Example**:
```javascript
// Before auto-sanitization
{
"type": "boolean",
"operation": "equals",
"singleValue": true // Binary operators shouldn't have this
}
// After auto-sanitization (automatic!)
{
"type": "boolean",
"operation": "equals"
// singleValue removed automatically
}
```
**Recovery tools**:
- `cleanStaleConnections` operation - removes broken connections
- `n8n_autofix_workflow({id})` - preview/apply fixes
---
## n8n_autofix_workflow (AUTO-FIX TOOL)
**Use when**: Validation errors need automatic fixes
```javascript
// Preview fixes (default - doesn't apply)
n8n_autofix_workflow({
id: "workflow-id",
applyFixes: false, // Preview mode
confidenceThreshold: "medium" // high, medium, low
})
// Apply fixes
n8n_autofix_workflow({
id: "workflow-id",
applyFixes: true
})
```
**Fix Types**:
- `expression-format` - Fix expression syntax
- `typeversion-correction` - Correct typeVersion
- `error-output-config` - Fix error output settings
- `webhook-missing-path` - Add missing webhook paths
- `typeversion-upgrade` - Upgrade to latest version
- `version-migration` - Apply version migrations
---
## Binary vs Unary Operators
**Binary operators** (compare two values):
- equals, notEquals, contains, notContains
- greaterThan, lessThan, startsWith, endsWith
- **Must NOT have** `singleValue: true`
**Unary operators** (check single value):
- isEmpty, isNotEmpty, true, false
- **Must have** `singleValue: true`
**Auto-sanitization fixes these automatically!**
---
## Handling Validation Errors
### Process
```
1. Read error message carefully
2. Check if it's a known false positive
3. Fix real errors
4. Validate again
5. Iterate until clean
```
### Common Errors
**"Required field missing"**
→ Add the field with appropriate value
**"Invalid value"**
→ Check allowed values in get_node output
**"Type mismatch"**
→ Convert to correct type (string/number/boolean)
**"Cannot have singleValue"**
→ Auto-sanitization will fix on next update
**"Missing operator metadata"**
→ Auto-sanitization will fix on next update
### False Positives
Some validation warnings may be acceptable:
- Optional best practices
- Node-specific edge cases
- Profile-dependent issues
Use **ai-friendly** profile to reduce false positives.
---
## Best Practices
### Do
- Use **runtime** profile for pre-deployment
- Validate after every configuration change
- Fix errors immediately (avg 58s)
- Iterate validation loop
- Trust auto-sanitization for operator issues
- Use `mode: "minimal"` for quick checks
- Use `n8n_autofix_workflow` for bulk fixes
- Activate workflows via API when ready (`activateWorkflow` operation)
### Don't
- Skip validation before deployment
- Ignore error messages
- Use strict profile during development (too many warnings)
- Assume validation passed (check result)
- Try to manually fix auto-sanitization issues
---
## Example: Complete Validation Workflow
```javascript
// Step 1: Get node requirements (quick check)
validate_node({
nodeType: "nodes-base.slack",
config: {},
mode: "minimal"
});
// → Know what's required
// Step 2: Configure node
const config = {
resource: "message",
operation: "post",
channel: "#general",
text: "Hello!"
};
// Step 3: Validate configuration (full validation)
const result = validate_node({
nodeType: "nodes-base.slack",
config,
profile: "runtime"
});
// Step 4: Check result
if (result.valid) {
console.log("Configuration valid!");
} else {
console.log("Errors:", result.errors);
// Fix and validate again
}
// Step 5: Validate in workflow context
validate_workflow({
workflow: {
nodes: [{...config as node...}],
connections: {...}
}
});
// Step 6: Apply auto-fixes if needed
n8n_autofix_workflow({
id: "workflow-id",
applyFixes: true
});
```
---
## Summary
**Key Points**:
1. Use **runtime** profile (balanced validation)
2. Validation loop: validate → fix (58s) → validate again
3. Auto-sanitization fixes operator structures automatically
4. Binary operators ≠ singleValue, Unary operators = singleValue: true
5. Iterate until validation passes
6. Use `n8n_autofix_workflow` for automatic fixes
**Tool Selection**:
- **validate_node({mode: "minimal"})**: Quick required fields check
- **validate_node({profile: "runtime"})**: Full config validation (**use this!**)
- **validate_workflow**: Complete workflow check
- **n8n_validate_workflow({id})**: Validate existing workflow
- **n8n_autofix_workflow({id})**: Auto-fix common issues
**Related**:
- [SEARCH_GUIDE.md](SEARCH_GUIDE.md) - Find nodes
- [WORKFLOW_GUIDE.md](WORKFLOW_GUIDE.md) - Build workflows

View File

@@ -0,0 +1,618 @@
# Workflow Management Tools Guide
Complete guide for creating, updating, and managing n8n workflows.
---
## Tool Availability
**Requires n8n API**: All tools in this guide need `N8N_API_URL` and `N8N_API_KEY` configured.
If unavailable, use template examples and validation-only workflows.
---
## n8n_create_workflow
**Speed**: 100-500ms
**Use when**: Creating new workflows from scratch
**Syntax**:
```javascript
n8n_create_workflow({
name: "Webhook to Slack", // Required
nodes: [...], // Required: array of nodes
connections: {...}, // Required: connections object
settings: {...} // Optional: workflow settings
})
```
**Returns**: Created workflow with ID
**Example**:
```javascript
n8n_create_workflow({
name: "Webhook to Slack",
nodes: [
{
id: "webhook-1",
name: "Webhook",
type: "n8n-nodes-base.webhook", // Full prefix!
typeVersion: 2,
position: [250, 300],
parameters: {
path: "slack-notify",
httpMethod: "POST"
}
},
{
id: "slack-1",
name: "Slack",
type: "n8n-nodes-base.slack",
typeVersion: 2,
position: [450, 300],
parameters: {
resource: "message",
operation: "post",
channel: "#general",
text: "={{$json.body.message}}"
}
}
],
connections: {
"Webhook": {
"main": [[{node: "Slack", type: "main", index: 0}]]
}
}
})
```
**Notes**:
- Workflows created **inactive** (activate with `activateWorkflow` operation)
- Auto-sanitization runs on creation
- Validate before creating for best results
---
## n8n_update_partial_workflow (MOST USED!)
**Speed**: 50-200ms | **Uses**: 38,287 (most used tool!)
**Use when**: Making incremental changes to workflows
**Common pattern**: 56s average between edits (iterative building!)
### 17 Operation Types
**Node Operations** (6 types):
1. `addNode` - Add new node
2. `removeNode` - Remove node by ID or name
3. `updateNode` - Update node properties (use dot notation)
4. `moveNode` - Change position
5. `enableNode` - Enable disabled node
6. `disableNode` - Disable active node
**Connection Operations** (5 types):
7. `addConnection` - Connect nodes (supports smart params)
8. `removeConnection` - Remove connection (supports ignoreErrors)
9. `rewireConnection` - Change connection target
10. `cleanStaleConnections` - Auto-remove broken connections
11. `replaceConnections` - Replace entire connections object
**Metadata Operations** (4 types):
12. `updateSettings` - Workflow settings
13. `updateName` - Rename workflow
14. `addTag` - Add tag
15. `removeTag` - Remove tag
**Activation Operations** (2 types):
16. `activateWorkflow` - Activate workflow for automatic execution
17. `deactivateWorkflow` - Deactivate workflow
### Intent Parameter (IMPORTANT!)
Always include `intent` for better responses:
```javascript
n8n_update_partial_workflow({
id: "workflow-id",
intent: "Add error handling for API failures", // Describe what you're doing
operations: [...]
})
```
### Smart Parameters
**IF nodes** - Use semantic branch names:
```javascript
{
type: "addConnection",
source: "IF",
target: "True Handler",
branch: "true" // Instead of sourceIndex: 0
}
{
type: "addConnection",
source: "IF",
target: "False Handler",
branch: "false" // Instead of sourceIndex: 1
}
```
**Switch nodes** - Use semantic case numbers:
```javascript
{
type: "addConnection",
source: "Switch",
target: "Handler A",
case: 0
}
{
type: "addConnection",
source: "Switch",
target: "Handler B",
case: 1
}
```
### AI Connection Types (8 types)
**Full support** for AI workflows:
```javascript
// Language Model
{
type: "addConnection",
source: "OpenAI Chat Model",
target: "AI Agent",
sourceOutput: "ai_languageModel"
}
// Tool
{
type: "addConnection",
source: "HTTP Request Tool",
target: "AI Agent",
sourceOutput: "ai_tool"
}
// Memory
{
type: "addConnection",
source: "Window Buffer Memory",
target: "AI Agent",
sourceOutput: "ai_memory"
}
// All 8 types:
// - ai_languageModel
// - ai_tool
// - ai_memory
// - ai_outputParser
// - ai_embedding
// - ai_vectorStore
// - ai_document
// - ai_textSplitter
```
### Property Removal with undefined
Remove properties by setting them to `undefined`:
```javascript
// Remove a property
{
type: "updateNode",
nodeName: "HTTP Request",
updates: { onError: undefined }
}
// Migrate from deprecated property
{
type: "updateNode",
nodeName: "HTTP Request",
updates: {
continueOnFail: undefined, // Remove old
onError: "continueErrorOutput" // Add new
}
}
```
### Activation Operations
```javascript
// Activate workflow
n8n_update_partial_workflow({
id: "workflow-id",
intent: "Activate workflow for production",
operations: [{type: "activateWorkflow"}]
})
// Deactivate workflow
n8n_update_partial_workflow({
id: "workflow-id",
intent: "Deactivate workflow for maintenance",
operations: [{type: "deactivateWorkflow"}]
})
```
### Example Usage
```javascript
n8n_update_partial_workflow({
id: "workflow-id",
intent: "Add transform node after IF condition",
operations: [
// Add node
{
type: "addNode",
node: {
name: "Transform",
type: "n8n-nodes-base.set",
position: [400, 300],
parameters: {}
}
},
// Connect it (smart parameter)
{
type: "addConnection",
source: "IF",
target: "Transform",
branch: "true" // Clear and semantic!
}
]
})
```
### Cleanup & Recovery
**cleanStaleConnections** - Remove broken connections:
```javascript
{type: "cleanStaleConnections"}
```
**rewireConnection** - Change target atomically:
```javascript
{
type: "rewireConnection",
source: "Webhook",
from: "Old Handler",
to: "New Handler"
}
```
**Best-effort mode** - Apply what works:
```javascript
n8n_update_partial_workflow({
id: "workflow-id",
operations: [...],
continueOnError: true // Don't fail if some operations fail
})
```
**Validate before applying**:
```javascript
n8n_update_partial_workflow({
id: "workflow-id",
operations: [...],
validateOnly: true // Preview without applying
})
```
---
## n8n_deploy_template (QUICK START!)
**Speed**: 200-500ms
**Use when**: Deploying a template directly to n8n instance
```javascript
n8n_deploy_template({
templateId: 2947, // Required: from n8n.io
name: "My Weather to Slack", // Optional: custom name
autoFix: true, // Default: auto-fix common issues
autoUpgradeVersions: true, // Default: upgrade node versions
stripCredentials: true // Default: remove credential refs
})
```
**Returns**:
- Workflow ID
- Required credentials
- Fixes applied
**Example**:
```javascript
// Deploy a webhook to Slack template
const result = n8n_deploy_template({
templateId: 2947,
name: "Production Slack Notifier"
});
// Result includes:
// - id: "new-workflow-id"
// - requiredCredentials: ["slack"]
// - fixesApplied: ["typeVersion upgraded", "expression format fixed"]
```
---
## n8n_workflow_versions (VERSION CONTROL)
**Use when**: Managing workflow history, rollback, cleanup
### List Versions
```javascript
n8n_workflow_versions({
mode: "list",
workflowId: "workflow-id",
limit: 10
})
```
### Get Specific Version
```javascript
n8n_workflow_versions({
mode: "get",
versionId: 123
})
```
### Rollback to Previous Version
```javascript
n8n_workflow_versions({
mode: "rollback",
workflowId: "workflow-id",
versionId: 123, // Optional: specific version
validateBefore: true // Default: validate before rollback
})
```
### Delete Versions
```javascript
// Delete specific version
n8n_workflow_versions({
mode: "delete",
workflowId: "workflow-id",
versionId: 123
})
// Delete all versions for workflow
n8n_workflow_versions({
mode: "delete",
workflowId: "workflow-id",
deleteAll: true
})
```
### Prune Old Versions
```javascript
n8n_workflow_versions({
mode: "prune",
workflowId: "workflow-id",
maxVersions: 10 // Keep 10 most recent
})
```
---
## n8n_test_workflow (TRIGGER EXECUTION)
**Use when**: Testing workflow execution
**Auto-detects** trigger type (webhook, form, chat)
```javascript
// Test webhook workflow
n8n_test_workflow({
workflowId: "workflow-id",
triggerType: "webhook", // Optional: auto-detected
httpMethod: "POST",
data: {message: "Hello!"},
waitForResponse: true,
timeout: 120000
})
// Test chat workflow
n8n_test_workflow({
workflowId: "workflow-id",
triggerType: "chat",
message: "Hello, AI agent!",
sessionId: "session-123" // For conversation continuity
})
```
---
## n8n_validate_workflow (by ID)
**Use when**: Validating workflow stored in n8n
```javascript
n8n_validate_workflow({
id: "workflow-id",
options: {
validateNodes: true,
validateConnections: true,
validateExpressions: true,
profile: "runtime"
}
})
```
---
## n8n_get_workflow
**Use when**: Retrieving workflow details
**Modes**:
- `full` (default) - Complete workflow JSON
- `details` - Full + execution stats
- `structure` - Nodes + connections only
- `minimal` - ID, name, active, tags
```javascript
// Full workflow
n8n_get_workflow({id: "workflow-id"})
// Just structure
n8n_get_workflow({id: "workflow-id", mode: "structure"})
// Minimal metadata
n8n_get_workflow({id: "workflow-id", mode: "minimal"})
```
---
## n8n_executions (EXECUTION MANAGEMENT)
**Use when**: Managing workflow executions
### Get Execution Details
```javascript
n8n_executions({
action: "get",
id: "execution-id",
mode: "summary" // preview, summary, filtered, full, error
})
// Error mode for debugging
n8n_executions({
action: "get",
id: "execution-id",
mode: "error",
includeStackTrace: true
})
```
### List Executions
```javascript
n8n_executions({
action: "list",
workflowId: "workflow-id",
status: "error", // success, error, waiting
limit: 100
})
```
### Delete Execution
```javascript
n8n_executions({
action: "delete",
id: "execution-id"
})
```
---
## Workflow Lifecycle
**Standard pattern**:
```
1. CREATE
n8n_create_workflow({...})
→ Returns workflow ID
2. VALIDATE
n8n_validate_workflow({id})
→ Check for errors
3. EDIT (iterative! 56s avg between edits)
n8n_update_partial_workflow({id, intent: "...", operations: [...]})
→ Make changes
4. VALIDATE AGAIN
n8n_validate_workflow({id})
→ Verify changes
5. ACTIVATE
n8n_update_partial_workflow({
id,
intent: "Activate workflow",
operations: [{type: "activateWorkflow"}]
})
→ Workflow now runs on triggers!
6. MONITOR
n8n_executions({action: "list", workflowId: id})
n8n_executions({action: "get", id: execution_id})
```
---
## Common Patterns from Telemetry
### Pattern 1: Edit → Validate (7,841 occurrences)
```javascript
n8n_update_partial_workflow({...})
// ↓ 23s (thinking about what to validate)
n8n_validate_workflow({id})
```
### Pattern 2: Validate → Fix (7,266 occurrences)
```javascript
n8n_validate_workflow({id})
// ↓ 58s (fixing errors)
n8n_update_partial_workflow({...})
```
### Pattern 3: Iterative Building (31,464 occurrences)
```javascript
update → update → update → ... (56s avg between edits)
```
**This shows**: Workflows are built **iteratively**, not in one shot!
---
## Best Practices
### Do
- Build workflows **iteratively** (avg 56s between edits)
- Include **intent** parameter for better responses
- Use **smart parameters** (branch, case) for clarity
- Validate **after** significant changes
- Use **atomic mode** (default) for critical updates
- Specify **sourceOutput** for AI connections
- Clean stale connections after node renames/deletions
- Use `n8n_deploy_template` for quick starts
- Activate workflows via API when ready
### Don't
- Try to build workflows in one shot
- Skip the intent parameter
- Use sourceIndex when branch/case available
- Skip validation before activation
- Forget to test workflows after creation
- Ignore auto-sanitization behavior
---
## Summary
**Most Important**:
1. **n8n_update_partial_workflow** is most-used tool (38,287 uses)
2. Include **intent** parameter for better responses
3. Workflows built **iteratively** (56s avg between edits)
4. Use **smart parameters** (branch="true", case=0) for clarity
5. **AI connections** supported (8 types with sourceOutput)
6. **Workflow activation** supported via API (`activateWorkflow` operation)
7. **Auto-sanitization** runs on all operations
8. Use **n8n_deploy_template** for quick starts
**New Tools**:
- `n8n_deploy_template` - Deploy templates directly
- `n8n_workflow_versions` - Version control & rollback
- `n8n_test_workflow` - Trigger execution
- `n8n_executions` - Manage executions
**Related**:
- [SEARCH_GUIDE.md](SEARCH_GUIDE.md) - Find nodes to add
- [VALIDATION_GUIDE.md](VALIDATION_GUIDE.md) - Validate workflows

View File

@@ -0,0 +1,789 @@
# Property Dependencies Guide
Deep dive into n8n property dependencies and displayOptions mechanism.
---
## What Are Property Dependencies?
**Definition**: Rules that control when fields are visible or required based on other field values.
**Mechanism**: `displayOptions` in node schema
**Purpose**:
- Show relevant fields only
- Hide irrelevant fields
- Simplify configuration UX
- Prevent invalid configurations
---
## displayOptions Structure
### Basic Format
```javascript
{
"name": "fieldName",
"type": "string",
"displayOptions": {
"show": {
"otherField": ["value1", "value2"]
}
}
}
```
**Translation**: Show `fieldName` when `otherField` equals "value1" OR "value2"
### Show vs Hide
#### show (Most Common)
**Show field when condition matches**:
```javascript
{
"name": "body",
"displayOptions": {
"show": {
"sendBody": [true]
}
}
}
```
**Meaning**: Show `body` when `sendBody = true`
#### hide (Less Common)
**Hide field when condition matches**:
```javascript
{
"name": "advanced",
"displayOptions": {
"hide": {
"simpleMode": [true]
}
}
}
```
**Meaning**: Hide `advanced` when `simpleMode = true`
### Multiple Conditions (AND Logic)
```javascript
{
"name": "body",
"displayOptions": {
"show": {
"sendBody": [true],
"method": ["POST", "PUT", "PATCH"]
}
}
}
```
**Meaning**: Show `body` when:
- `sendBody = true` AND
- `method IN (POST, PUT, PATCH)`
**All conditions must match** (AND logic)
### Multiple Values (OR Logic)
```javascript
{
"name": "someField",
"displayOptions": {
"show": {
"method": ["POST", "PUT", "PATCH"]
}
}
}
```
**Meaning**: Show `someField` when:
- `method = POST` OR
- `method = PUT` OR
- `method = PATCH`
**Any value matches** (OR logic)
---
## Common Dependency Patterns
### Pattern 1: Boolean Toggle
**Use case**: Optional feature flag
**Example**: HTTP Request sendBody
```javascript
// Field: sendBody (boolean)
{
"name": "sendBody",
"type": "boolean",
"default": false
}
// Field: body (depends on sendBody)
{
"name": "body",
"displayOptions": {
"show": {
"sendBody": [true]
}
}
}
```
**Flow**:
1. User sees sendBody checkbox
2. When checked → body field appears
3. When unchecked → body field hides
### Pattern 2: Resource/Operation Cascade
**Use case**: Different operations show different fields
**Example**: Slack message operations
```javascript
// Operation: post
{
"name": "channel",
"displayOptions": {
"show": {
"resource": ["message"],
"operation": ["post"]
}
}
}
// Operation: update
{
"name": "messageId",
"displayOptions": {
"show": {
"resource": ["message"],
"operation": ["update"]
}
}
}
```
**Flow**:
1. User selects resource="message"
2. User selects operation="post" → sees channel
3. User changes to operation="update" → channel hides, messageId shows
### Pattern 3: Type-Specific Configuration
**Use case**: Different types need different fields
**Example**: IF node conditions
```javascript
// String operations
{
"name": "value2",
"displayOptions": {
"show": {
"conditions.string.0.operation": ["equals", "notEquals", "contains"]
}
}
}
// Unary operations (isEmpty) don't show value2
{
"displayOptions": {
"hide": {
"conditions.string.0.operation": ["isEmpty", "isNotEmpty"]
}
}
}
```
### Pattern 4: Method-Specific Fields
**Use case**: HTTP methods have different options
**Example**: HTTP Request
```javascript
// Query parameters (all methods can have)
{
"name": "queryParameters",
"displayOptions": {
"show": {
"sendQuery": [true]
}
}
}
// Body (only certain methods)
{
"name": "body",
"displayOptions": {
"show": {
"sendBody": [true],
"method": ["POST", "PUT", "PATCH", "DELETE"]
}
}
}
```
---
## Finding Property Dependencies
### Using get_node with search_properties Mode
```javascript
// Find properties related to "body"
get_node({
nodeType: "nodes-base.httpRequest",
mode: "search_properties",
propertyQuery: "body"
});
```
### Using get_node with Full Detail
```javascript
// Get complete schema with displayOptions
get_node({
nodeType: "nodes-base.httpRequest",
detail: "full"
});
```
### When to Use
**✅ Use when**:
- Validation fails with "missing field" but you don't see that field
- A field appears/disappears unexpectedly
- You need to understand what controls field visibility
- Building dynamic configuration tools
**❌ Don't use when**:
- Simple configuration (use `get_node` with standard detail)
- Just starting configuration
- Field requirements are obvious
---
## Complex Dependency Examples
### Example 1: HTTP Request Complete Flow
**Scenario**: Configuring POST with JSON body
**Step 1**: Set method
```javascript
{
"method": "POST"
// → sendBody becomes visible
}
```
**Step 2**: Enable body
```javascript
{
"method": "POST",
"sendBody": true
// → body field becomes visible AND required
}
```
**Step 3**: Configure body
```javascript
{
"method": "POST",
"sendBody": true,
"body": {
"contentType": "json"
// → content field becomes visible AND required
}
}
```
**Step 4**: Add content
```javascript
{
"method": "POST",
"sendBody": true,
"body": {
"contentType": "json",
"content": {
"name": "John",
"email": "john@example.com"
}
}
}
// ✅ Valid!
```
**Dependency chain**:
```
method=POST
→ sendBody visible
→ sendBody=true
→ body visible + required
→ body.contentType=json
→ body.content visible + required
```
### Example 2: IF Node Operator Dependencies
**Scenario**: String comparison with different operators
**Binary operator** (equals):
```javascript
{
"conditions": {
"string": [
{
"operation": "equals"
// → value1 required
// → value2 required
// → singleValue should NOT be set
}
]
}
}
```
**Unary operator** (isEmpty):
```javascript
{
"conditions": {
"string": [
{
"operation": "isEmpty"
// → value1 required
// → value2 should NOT be set
// → singleValue should be true (auto-added)
}
]
}
}
```
**Dependency table**:
| Operator | value1 | value2 | singleValue |
|---|---|---|---|
| equals | Required | Required | false |
| notEquals | Required | Required | false |
| contains | Required | Required | false |
| isEmpty | Required | Hidden | true |
| isNotEmpty | Required | Hidden | true |
### Example 3: Slack Operation Matrix
**Scenario**: Different Slack operations show different fields
```javascript
// post message
{
"resource": "message",
"operation": "post"
// Shows: channel (required), text (required), attachments, blocks
}
// update message
{
"resource": "message",
"operation": "update"
// Shows: messageId (required), text (required), channel (optional)
}
// delete message
{
"resource": "message",
"operation": "delete"
// Shows: messageId (required), channel (required)
// Hides: text, attachments, blocks
}
// get message
{
"resource": "message",
"operation": "get"
// Shows: messageId (required), channel (required)
// Hides: text, attachments, blocks
}
```
**Field visibility matrix**:
| Field | post | update | delete | get |
|---|---|---|---|---|
| channel | Required | Optional | Required | Required |
| text | Required | Required | Hidden | Hidden |
| messageId | Hidden | Required | Required | Required |
| attachments | Optional | Optional | Hidden | Hidden |
| blocks | Optional | Optional | Hidden | Hidden |
---
## Nested Dependencies
### What Are They?
**Definition**: Dependencies within object properties
**Example**: HTTP Request body.contentType controls body.content structure
```javascript
{
"body": {
"contentType": "json",
// → content expects JSON object
"content": {
"key": "value"
}
}
}
{
"body": {
"contentType": "form-data",
// → content expects form fields array
"content": [
{
"name": "field1",
"value": "value1"
}
]
}
}
```
### How to Handle
**Strategy**: Configure parent first, then children
```javascript
// Step 1: Parent
{
"body": {
"contentType": "json" // Set parent first
}
}
// Step 2: Children (structure determined by parent)
{
"body": {
"contentType": "json",
"content": { // JSON object format
"key": "value"
}
}
}
```
---
## Auto-Sanitization and Dependencies
### What Auto-Sanitization Fixes
**Operator structure issues** (IF/Switch nodes):
**Example**: singleValue property
```javascript
// You configure (missing singleValue)
{
"type": "boolean",
"operation": "isEmpty"
// Missing singleValue
}
// Auto-sanitization adds it
{
"type": "boolean",
"operation": "isEmpty",
"singleValue": true // ✅ Added automatically
}
```
### What It Doesn't Fix
**Missing required fields**:
```javascript
// You configure (missing channel)
{
"resource": "message",
"operation": "post",
"text": "Hello"
// Missing required field: channel
}
// Auto-sanitization does NOT add
// You must add it yourself
{
"resource": "message",
"operation": "post",
"channel": "#general", // ← You must add
"text": "Hello"
}
```
---
## Troubleshooting Dependencies
### Problem 1: "Field X is required but not visible"
**Error**:
```json
{
"type": "missing_required",
"property": "body",
"message": "body is required"
}
```
**But you don't see body field in configuration!**
**Solution**:
```javascript
// Check field dependencies using search_properties
get_node({
nodeType: "nodes-base.httpRequest",
mode: "search_properties",
propertyQuery: "body"
});
// Find that body shows when sendBody=true
// Add sendBody
{
"method": "POST",
"sendBody": true, // ← Now body appears!
"body": {...}
}
```
### Problem 2: "Field disappears when I change operation"
**Scenario**:
```javascript
// Working configuration
{
"resource": "message",
"operation": "post",
"channel": "#general",
"text": "Hello"
}
// Change operation
{
"resource": "message",
"operation": "update", // Changed
"channel": "#general", // Still here
"text": "Updated" // Still here
// Missing: messageId (required for update!)
}
```
**Validation error**: "messageId is required"
**Why**: Different operation = different required fields
**Solution**:
```javascript
// Check requirements for new operation
get_node({
nodeType: "nodes-base.slack"
});
// Configure for update operation
{
"resource": "message",
"operation": "update",
"messageId": "1234567890", // Required for update
"text": "Updated",
"channel": "#general" // Optional for update
}
```
### Problem 3: "Validation passes but field doesn't save"
**Scenario**: Field hidden by dependencies after validation
**Example**:
```javascript
// Configure
{
"method": "GET",
"sendBody": true, // ❌ GET doesn't support body
"body": {...} // This will be stripped
}
// After save
{
"method": "GET"
// body removed because method=GET hides it
}
```
**Solution**: Respect dependencies from the start
```javascript
// Correct approach - check property dependencies
get_node({
nodeType: "nodes-base.httpRequest",
mode: "search_properties",
propertyQuery: "body"
});
// See that body only shows for POST/PUT/PATCH/DELETE
// Use correct method
{
"method": "POST",
"sendBody": true,
"body": {...}
}
```
---
## Advanced Patterns
### Pattern 1: Conditional Required with Fallback
**Example**: Channel can be string OR expression
```javascript
// Option 1: String
{
"channel": "#general"
}
// Option 2: Expression
{
"channel": "={{$json.channelName}}"
}
// Validation accepts both
```
### Pattern 2: Mutually Exclusive Fields
**Example**: Use either ID or name, not both
```javascript
// Use messageId
{
"messageId": "1234567890"
// name not needed
}
// OR use messageName
{
"messageName": "thread-name"
// messageId not needed
}
// Dependencies ensure only one is required
```
### Pattern 3: Progressive Complexity
**Example**: Simple mode vs advanced mode
```javascript
// Simple mode
{
"mode": "simple",
"text": "{{$json.message}}"
// Advanced fields hidden
}
// Advanced mode
{
"mode": "advanced",
"attachments": [...],
"blocks": [...],
"metadata": {...}
// Simple field hidden, advanced fields shown
}
```
---
## Best Practices
### ✅ Do
1. **Check dependencies when stuck**
```javascript
get_node({nodeType: "...", mode: "search_properties", propertyQuery: "..."});
```
2. **Configure parent properties first**
```javascript
// First: method, resource, operation
// Then: dependent fields
```
3. **Validate after changing operation**
```javascript
// Operation changed → requirements changed
validate_node({nodeType: "...", config: {...}, profile: "runtime"});
```
4. **Read validation errors for dependency hints**
```
Error: "body required when sendBody=true"
→ Hint: Set sendBody=true to enable body
```
### ❌ Don't
1. **Don't ignore dependency errors**
```javascript
// Error: "body not visible" → Check displayOptions
```
2. **Don't hardcode all possible fields**
```javascript
// Bad: Adding fields that will be hidden
```
3. **Don't assume operations are identical**
```javascript
// Each operation has unique requirements
```
---
## Summary
**Key Concepts**:
- `displayOptions` control field visibility
- `show` = field appears when conditions match
- `hide` = field disappears when conditions match
- Multiple conditions = AND logic
- Multiple values = OR logic
**Common Patterns**:
1. Boolean toggle (sendBody → body)
2. Resource/operation cascade (different operations → different fields)
3. Type-specific config (string vs boolean conditions)
4. Method-specific fields (GET vs POST)
**Troubleshooting**:
- Field required but not visible → Check dependencies
- Field disappears after change → Operation changed requirements
- Field doesn't save → Hidden by dependencies
**Tools**:
- `get_node({mode: "search_properties"})` - Find property dependencies
- `get_node({detail: "full"})` - See complete schema with displayOptions
- `get_node` - See operation requirements (standard detail)
- Validation errors - Hints about dependencies
**Related Files**:
- **[SKILL.md](SKILL.md)** - Main configuration guide
- **[OPERATION_PATTERNS.md](OPERATION_PATTERNS.md)** - Common patterns by node type

View File

@@ -0,0 +1,913 @@
# Operation Patterns Guide
Common node configuration patterns organized by node type and operation.
---
## Overview
**Purpose**: Quick reference for common node configurations
**Coverage**: Top 20 most-used nodes from 525 available
**Pattern format**:
- Minimal valid configuration
- Common options
- Real-world examples
- Gotchas and tips
---
## HTTP & API Nodes
### HTTP Request (nodes-base.httpRequest)
Most versatile node for HTTP operations
#### GET Request
**Minimal**:
```javascript
{
"method": "GET",
"url": "https://api.example.com/users",
"authentication": "none"
}
```
**With query parameters**:
```javascript
{
"method": "GET",
"url": "https://api.example.com/users",
"authentication": "none",
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "limit",
"value": "100"
},
{
"name": "offset",
"value": "={{$json.offset}}"
}
]
}
}
```
**With authentication**:
```javascript
{
"method": "GET",
"url": "https://api.example.com/users",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "httpHeaderAuth"
}
```
#### POST with JSON
**Minimal**:
```javascript
{
"method": "POST",
"url": "https://api.example.com/users",
"authentication": "none",
"sendBody": true,
"body": {
"contentType": "json",
"content": {
"name": "John Doe",
"email": "john@example.com"
}
}
}
```
**With expressions**:
```javascript
{
"method": "POST",
"url": "https://api.example.com/users",
"authentication": "none",
"sendBody": true,
"body": {
"contentType": "json",
"content": {
"name": "={{$json.name}}",
"email": "={{$json.email}}",
"metadata": {
"source": "n8n",
"timestamp": "={{$now.toISO()}}"
}
}
}
}
```
**Gotcha**: Remember `sendBody: true` for POST/PUT/PATCH!
#### PUT/PATCH Request
**Pattern**: Same as POST, but method changes
```javascript
{
"method": "PUT", // or "PATCH"
"url": "https://api.example.com/users/123",
"authentication": "none",
"sendBody": true,
"body": {
"contentType": "json",
"content": {
"name": "Updated Name"
}
}
}
```
#### DELETE Request
**Minimal** (no body):
```javascript
{
"method": "DELETE",
"url": "https://api.example.com/users/123",
"authentication": "none"
}
```
**With body** (some APIs allow):
```javascript
{
"method": "DELETE",
"url": "https://api.example.com/users",
"authentication": "none",
"sendBody": true,
"body": {
"contentType": "json",
"content": {
"ids": ["123", "456"]
}
}
}
```
---
### Webhook (nodes-base.webhook)
Most common trigger - 813 searches!
#### Basic Webhook
**Minimal**:
```javascript
{
"path": "my-webhook",
"httpMethod": "POST",
"responseMode": "onReceived"
}
```
**Gotcha**: Webhook data is under `$json.body`, not `$json`!
```javascript
// ❌ Wrong
{
"text": "={{$json.email}}"
}
// ✅ Correct
{
"text": "={{$json.body.email}}"
}
```
#### Webhook with Authentication
**Header auth**:
```javascript
{
"path": "secure-webhook",
"httpMethod": "POST",
"responseMode": "onReceived",
"authentication": "headerAuth",
"options": {
"responseCode": 200,
"responseData": "{\n \"success\": true\n}"
}
}
```
#### Webhook Returning Data
**Custom response**:
```javascript
{
"path": "my-webhook",
"httpMethod": "POST",
"responseMode": "lastNode", // Return data from last node
"options": {
"responseCode": 201,
"responseHeaders": {
"entries": [
{
"name": "Content-Type",
"value": "application/json"
}
]
}
}
}
```
---
## Communication Nodes
### Slack (nodes-base.slack)
Popular choice for AI agent workflows
#### Post Message
**Minimal**:
```javascript
{
"resource": "message",
"operation": "post",
"channel": "#general",
"text": "Hello from n8n!"
}
```
**With dynamic content**:
```javascript
{
"resource": "message",
"operation": "post",
"channel": "={{$json.channel}}",
"text": "New user: {{$json.name}} ({{$json.email}})"
}
```
**With attachments**:
```javascript
{
"resource": "message",
"operation": "post",
"channel": "#alerts",
"text": "Error Alert",
"attachments": [
{
"color": "#ff0000",
"fields": [
{
"title": "Error Type",
"value": "={{$json.errorType}}"
},
{
"title": "Timestamp",
"value": "={{$now.toLocaleString()}}"
}
]
}
]
}
```
**Gotcha**: Channel must start with `#` for public channels or be a channel ID!
#### Update Message
**Minimal**:
```javascript
{
"resource": "message",
"operation": "update",
"messageId": "1234567890.123456", // From previous message post
"text": "Updated message content"
}
```
**Note**: `messageId` required, `channel` optional (can be inferred)
#### Create Channel
**Minimal**:
```javascript
{
"resource": "channel",
"operation": "create",
"name": "new-project-channel", // Lowercase, no spaces
"isPrivate": false
}
```
**Gotcha**: Channel name must be lowercase, no spaces, 1-80 chars!
---
### Gmail (nodes-base.gmail)
Popular for email automation
#### Send Email
**Minimal**:
```javascript
{
"resource": "message",
"operation": "send",
"to": "user@example.com",
"subject": "Hello from n8n",
"message": "This is the email body"
}
```
**With dynamic content**:
```javascript
{
"resource": "message",
"operation": "send",
"to": "={{$json.email}}",
"subject": "Order Confirmation #{{$json.orderId}}",
"message": "Dear {{$json.name}},\n\nYour order has been confirmed.\n\nThank you!",
"options": {
"ccList": "admin@example.com",
"replyTo": "support@example.com"
}
}
```
#### Get Email
**Minimal**:
```javascript
{
"resource": "message",
"operation": "getAll",
"returnAll": false,
"limit": 10
}
```
**With filters**:
```javascript
{
"resource": "message",
"operation": "getAll",
"returnAll": false,
"limit": 50,
"filters": {
"q": "is:unread from:important@example.com",
"labelIds": ["INBOX"]
}
}
```
---
## Database Nodes
### Postgres (nodes-base.postgres)
Database operations - 456 templates
#### Execute Query
**Minimal** (SELECT):
```javascript
{
"operation": "executeQuery",
"query": "SELECT * FROM users WHERE active = true LIMIT 100"
}
```
**With parameters** (SQL injection prevention):
```javascript
{
"operation": "executeQuery",
"query": "SELECT * FROM users WHERE email = $1 AND active = $2",
"additionalFields": {
"mode": "list",
"queryParameters": "user@example.com,true"
}
}
```
**Gotcha**: ALWAYS use parameterized queries for user input!
```javascript
// ❌ BAD - SQL injection risk!
{
"query": "SELECT * FROM users WHERE email = '{{$json.email}}'"
}
// ✅ GOOD - Parameterized
{
"query": "SELECT * FROM users WHERE email = $1",
"additionalFields": {
"mode": "list",
"queryParameters": "={{$json.email}}"
}
}
```
#### Insert
**Minimal**:
```javascript
{
"operation": "insert",
"table": "users",
"columns": "name,email,created_at",
"additionalFields": {
"mode": "list",
"queryParameters": "John Doe,john@example.com,NOW()"
}
}
```
**With expressions**:
```javascript
{
"operation": "insert",
"table": "users",
"columns": "name,email,metadata",
"additionalFields": {
"mode": "list",
"queryParameters": "={{$json.name}},={{$json.email}},{{JSON.stringify($json)}}"
}
}
```
#### Update
**Minimal**:
```javascript
{
"operation": "update",
"table": "users",
"updateKey": "id",
"columns": "name,email",
"additionalFields": {
"mode": "list",
"queryParameters": "={{$json.id}},Updated Name,newemail@example.com"
}
}
```
---
## Data Transformation Nodes
### Set (nodes-base.set)
Most used transformation - 68% of workflows!
#### Set Fixed Values
**Minimal**:
```javascript
{
"mode": "manual",
"duplicateItem": false,
"assignments": {
"assignments": [
{
"name": "status",
"value": "active",
"type": "string"
},
{
"name": "count",
"value": 100,
"type": "number"
}
]
}
}
```
#### Set from Input Data
**Mapping data**:
```javascript
{
"mode": "manual",
"duplicateItem": false,
"assignments": {
"assignments": [
{
"name": "fullName",
"value": "={{$json.firstName}} {{$json.lastName}}",
"type": "string"
},
{
"name": "email",
"value": "={{$json.email.toLowerCase()}}",
"type": "string"
},
{
"name": "timestamp",
"value": "={{$now.toISO()}}",
"type": "string"
}
]
}
}
```
**Gotcha**: Use correct `type` for each field!
```javascript
// ❌ Wrong type
{
"name": "age",
"value": "25", // String
"type": "string" // Will be string "25"
}
// ✅ Correct type
{
"name": "age",
"value": 25, // Number
"type": "number" // Will be number 25
}
```
---
### Code (nodes-base.code)
JavaScript execution - 42% of workflows
#### Simple Transformation
**Minimal**:
```javascript
{
"mode": "runOnceForAllItems",
"jsCode": "return $input.all().map(item => ({\n json: {\n name: item.json.name.toUpperCase(),\n email: item.json.email\n }\n}));"
}
```
**Per-item processing**:
```javascript
{
"mode": "runOnceForEachItem",
"jsCode": "// Process each item\nconst data = $input.item.json;\n\nreturn {\n json: {\n fullName: `${data.firstName} ${data.lastName}`,\n email: data.email.toLowerCase(),\n timestamp: new Date().toISOString()\n }\n};"
}
```
**Gotcha**: In Code nodes, use `$input.item.json` or `$input.all()`, NOT `{{...}}`!
```javascript
// ❌ Wrong - expressions don't work in Code nodes
{
"jsCode": "const name = '={{$json.name}}';"
}
// ✅ Correct - direct access
{
"jsCode": "const name = $input.item.json.name;"
}
```
---
## Conditional Nodes
### IF (nodes-base.if)
Conditional logic - 38% of workflows
#### String Comparison
**Equals** (binary):
```javascript
{
"conditions": {
"string": [
{
"value1": "={{$json.status}}",
"operation": "equals",
"value2": "active"
}
]
}
}
```
**Contains** (binary):
```javascript
{
"conditions": {
"string": [
{
"value1": "={{$json.email}}",
"operation": "contains",
"value2": "@example.com"
}
]
}
}
```
**isEmpty** (unary):
```javascript
{
"conditions": {
"string": [
{
"value1": "={{$json.email}}",
"operation": "isEmpty"
// No value2 - unary operator
// singleValue: true added by auto-sanitization
}
]
}
}
```
**Gotcha**: Unary operators (isEmpty, isNotEmpty) don't need value2!
#### Number Comparison
**Greater than**:
```javascript
{
"conditions": {
"number": [
{
"value1": "={{$json.age}}",
"operation": "larger",
"value2": 18
}
]
}
}
```
#### Boolean Comparison
**Is true**:
```javascript
{
"conditions": {
"boolean": [
{
"value1": "={{$json.isActive}}",
"operation": "true"
// Unary - no value2
}
]
}
}
```
#### Multiple Conditions (AND)
**All must match**:
```javascript
{
"conditions": {
"string": [
{
"value1": "={{$json.status}}",
"operation": "equals",
"value2": "active"
}
],
"number": [
{
"value1": "={{$json.age}}",
"operation": "larger",
"value2": 18
}
]
},
"combineOperation": "all" // AND logic
}
```
#### Multiple Conditions (OR)
**Any can match**:
```javascript
{
"conditions": {
"string": [
{
"value1": "={{$json.status}}",
"operation": "equals",
"value2": "active"
},
{
"value1": "={{$json.status}}",
"operation": "equals",
"value2": "pending"
}
]
},
"combineOperation": "any" // OR logic
}
```
---
### Switch (nodes-base.switch)
Multi-way routing - 18% of workflows
#### Basic Switch
**Minimal**:
```javascript
{
"mode": "rules",
"rules": {
"rules": [
{
"conditions": {
"string": [
{
"value1": "={{$json.status}}",
"operation": "equals",
"value2": "active"
}
]
}
},
{
"conditions": {
"string": [
{
"value1": "={{$json.status}}",
"operation": "equals",
"value2": "pending"
}
]
}
}
]
},
"fallbackOutput": "extra" // Catch-all for non-matching
}
```
**Gotcha**: Number of rules must match number of outputs!
---
## AI Nodes
### OpenAI (nodes-langchain.openAi)
AI operations - 234 templates
#### Chat Completion
**Minimal**:
```javascript
{
"resource": "chat",
"operation": "complete",
"messages": {
"values": [
{
"role": "user",
"content": "={{$json.prompt}}"
}
]
}
}
```
**With system prompt**:
```javascript
{
"resource": "chat",
"operation": "complete",
"messages": {
"values": [
{
"role": "system",
"content": "You are a helpful assistant specialized in customer support."
},
{
"role": "user",
"content": "={{$json.userMessage}}"
}
]
},
"options": {
"temperature": 0.7,
"maxTokens": 500
}
}
```
---
## Schedule Nodes
### Schedule Trigger (nodes-base.scheduleTrigger)
Time-based workflows - 28% have schedule triggers
#### Daily at Specific Time
**Minimal**:
```javascript
{
"rule": {
"interval": [
{
"field": "hours",
"hoursInterval": 24
}
],
"hour": 9,
"minute": 0,
"timezone": "America/New_York"
}
}
```
**Gotcha**: Always set timezone explicitly!
```javascript
// ❌ Bad - uses server timezone
{
"rule": {
"interval": [...]
}
}
// ✅ Good - explicit timezone
{
"rule": {
"interval": [...],
"timezone": "America/New_York"
}
}
```
#### Every N Minutes
**Minimal**:
```javascript
{
"rule": {
"interval": [
{
"field": "minutes",
"minutesInterval": 15
}
]
}
}
```
#### Cron Expression
**Advanced scheduling**:
```javascript
{
"mode": "cron",
"cronExpression": "0 */2 * * *", // Every 2 hours
"timezone": "America/New_York"
}
```
---
## Summary
**Key Patterns by Category**:
| Category | Most Common | Key Gotcha |
|---|---|---|
| HTTP/API | GET, POST JSON | Remember sendBody: true |
| Webhooks | POST receiver | Data under $json.body |
| Communication | Slack post | Channel format (#name) |
| Database | SELECT with params | Use parameterized queries |
| Transform | Set assignments | Correct type per field |
| Conditional | IF string equals | Unary vs binary operators |
| AI | OpenAI chat | System + user messages |
| Schedule | Daily at time | Set timezone explicitly |
**Configuration Approach**:
1. Use patterns as starting point
2. Adapt to your use case
3. Validate configuration
4. Iterate based on errors
5. Deploy when valid
**Related Files**:
- **[SKILL.md](SKILL.md)** - Configuration workflow and philosophy
- **[DEPENDENCIES.md](DEPENDENCIES.md)** - Property dependency rules

View File

@@ -0,0 +1,364 @@
# n8n Node Configuration
Expert guidance for operation-aware node configuration with property dependencies.
## Overview
**Skill Name**: n8n Node Configuration
**Priority**: Medium
**Purpose**: Teach operation-aware configuration with progressive discovery and dependency awareness
## The Problem This Solves
Node configuration patterns:
- get_node_essentials is the primary discovery tool (18s avg from search → essentials)
- 91.7% success rate with essentials-based configuration
- 56 seconds average between configuration edits
**Key insight**: Most configurations only need essentials, not full schema!
## What This Skill Teaches
### Core Concepts
1. **Operation-Aware Configuration**
- Resource + operation determine required fields
- Different operations = different requirements
- Always check requirements when changing operation
2. **Property Dependencies**
- Fields appear/disappear based on other field values
- displayOptions control visibility
- Conditional required fields
- Understanding dependency chains
3. **Progressive Discovery**
- Start with get_node_essentials (91.7% success)
- Escalate to get_property_dependencies if needed
- Use get_node_info only when necessary
- Right tool for right job
4. **Configuration Workflow**
- Identify → Discover → Configure → Validate → Iterate
- Average 2-3 validation cycles
- Read errors for dependency hints
- 56 seconds between edits average
5. **Common Patterns**
- Resource/operation nodes (Slack, Sheets)
- HTTP-based nodes (HTTP Request, Webhook)
- Database nodes (Postgres, MySQL)
- Conditional logic nodes (IF, Switch)
## File Structure
```
n8n-node-configuration/
├── SKILL.md (692 lines)
│ Main configuration guide
│ - Configuration philosophy (progressive disclosure)
│ - Core concepts (operation-aware, dependencies)
│ - Configuration workflow (8-step process)
│ - get_node_essentials vs get_node_info
│ - Property dependencies deep dive
│ - Common node patterns (4 categories)
│ - Operation-specific examples
│ - Conditional requirements
│ - Anti-patterns and best practices
│
├── DEPENDENCIES.md (671 lines)
│ Property dependencies reference
│ - displayOptions mechanism
│ - show vs hide rules
│ - Multiple conditions (AND logic)
│ - Multiple values (OR logic)
│ - 4 common dependency patterns
│ - Using get_property_dependencies
│ - Complex dependency examples
│ - Nested dependencies
│ - Auto-sanitization interaction
│ - Troubleshooting guide
│ - Advanced patterns
│
├── OPERATION_PATTERNS.md (783 lines)
│ Common configurations by node type
│ - HTTP Request (GET/POST/PUT/DELETE)
│ - Webhook (basic/auth/response)
│ - Slack (post/update/create)
│ - Gmail (send/get)
│ - Postgres (query/insert/update)
│ - Set (values/mapping)
│ - Code (per-item/all-items)
│ - IF (string/number/boolean)
│ - Switch (rules/fallback)
│ - OpenAI (chat completion)
│ - Schedule (daily/interval/cron)
│ - Gotchas and tips for each
│
└── README.md (this file)
Skill metadata and statistics
```
**Total**: ~2,146 lines across 4 files + 4 evaluations
## Usage Statistics
Configuration metrics:
| Metric | Value | Insight |
|---|---|---|
| get_node_essentials | Primary tool | Most popular discovery pattern |
| Success rate (essentials) | 91.7% | Essentials sufficient for most |
| Avg time search→essentials | 18 seconds | Fast discovery workflow |
| Avg time between edits | 56 seconds | Iterative configuration |
## Tool Usage Pattern
**Most common discovery pattern**:
```
search_nodes → get_node_essentials (18s average)
```
**Configuration cycle**:
```
get_node_essentials → configure → validate → iterate (56s avg per edit)
```
## Key Insights
### 1. Progressive Disclosure Works
**91.7% success rate** with get_node_essentials proves most configurations don't need full schema.
**Strategy**:
1. Start with essentials
2. Escalate to dependencies if stuck
3. Use full schema only when necessary
### 2. Operations Determine Requirements
**Same node, different operation = different requirements**
Example: Slack message
- `operation="post"` → needs channel + text
- `operation="update"` → needs messageId + text (different!)
### 3. Dependencies Control Visibility
**Fields appear/disappear based on other values**
Example: HTTP Request
- `method="GET"` → body hidden
- `method="POST"` + `sendBody=true` → body required
### 4. Configuration is Iterative
**Average 56 seconds between edits** shows configuration is iterative, not one-shot.
**Normal workflow**:
1. Configure minimal
2. Validate → error
3. Add missing field
4. Validate → error
5. Adjust value
6. Validate → valid ✅
### 5. Common Gotchas Exist
**Top 5 gotchas** from patterns:
1. Webhook data under `$json.body` (not `$json`)
2. POST needs `sendBody: true`
3. Slack channel format (`#name`)
4. SQL parameterized queries (injection prevention)
5. Timezone must be explicit (schedule nodes)
## Usage Examples
### Example 1: Basic Configuration Flow
```javascript
// Step 1: Get essentials
const info = get_node_essentials({
nodeType: "nodes-base.slack"
});
// Step 2: Configure for operation
{
"resource": "message",
"operation": "post",
"channel": "#general",
"text": "Hello!"
}
// Step 3: Validate
validate_node_operation({...});
// ✅ Valid!
```
### Example 2: Handling Dependencies
```javascript
// Step 1: Configure HTTP POST
{
"method": "POST",
"url": "https://api.example.com/create"
}
// Step 2: Validate → Error: "sendBody required"
// Step 3: Check dependencies
get_property_dependencies({
nodeType: "nodes-base.httpRequest"
});
// Shows: body visible when sendBody=true
// Step 4: Fix
{
"method": "POST",
"url": "https://api.example.com/create",
"sendBody": true,
"body": {
"contentType": "json",
"content": {...}
}
}
// ✅ Valid!
```
### Example 3: Operation Change
```javascript
// Initial config (post operation)
{
"resource": "message",
"operation": "post",
"channel": "#general",
"text": "Hello"
}
// Change operation
{
"resource": "message",
"operation": "update", // Changed!
// Need to check new requirements
}
// Get essentials for update operation
get_node_essentials({nodeType: "nodes-base.slack"});
// Shows: messageId required, channel optional
// Correct config
{
"resource": "message",
"operation": "update",
"messageId": "1234567890.123456",
"text": "Updated"
}
```
## When This Skill Activates
**Trigger phrases**:
- "how to configure"
- "what fields are required"
- "property dependencies"
- "get_node_essentials vs get_node_info"
- "operation-specific"
- "field not visible"
**Common scenarios**:
- Configuring new nodes
- Understanding required fields
- Field appears/disappears unexpectedly
- Choosing between discovery tools
- Switching operations
- Learning common patterns
## Integration with Other Skills
### Works With:
- **n8n MCP Tools Expert** - How to call discovery tools correctly
- **n8n Validation Expert** - Interpret missing_required errors
- **n8n Expression Syntax** - Configure expression fields
- **n8n Workflow Patterns** - Apply patterns with proper node config
### Complementary:
- Use MCP Tools Expert to learn tool selection
- Use Validation Expert to fix configuration errors
- Use Expression Syntax for dynamic field values
- Use Workflow Patterns to understand node relationships
## Testing
**Evaluations**: 4 test scenarios
1. **eval-001-property-dependencies.json**
- Tests understanding of displayOptions
- Guides to get_property_dependencies
- Explains conditional requirements
2. **eval-002-operation-specific-config.json**
- Tests operation-aware configuration
- Identifies resource + operation pattern
- References OPERATION_PATTERNS.md
3. **eval-003-conditional-fields.json**
- Tests unary vs binary operators
- Explains singleValue dependency
- Mentions auto-sanitization
4. **eval-004-essentials-vs-info.json**
- Tests tool selection knowledge
- Explains progressive disclosure
- Provides success rate statistics
## Success Metrics
**Before this skill**:
- Using get_node_info for everything (slow, overwhelming)
- Not understanding property dependencies
- Confused when fields appear/disappear
- Not aware of operation-specific requirements
- Trial and error configuration
**After this skill**:
- Start with get_node_essentials (91.7% success)
- Understand displayOptions mechanism
- Predict field visibility based on dependencies
- Check requirements when changing operations
- Systematic configuration approach
- Know common patterns by node type
## Coverage
**Node types covered**: Top 20 most-used nodes
| Category | Nodes | Coverage |
|---|---|---|
| HTTP/API | HTTP Request, Webhook | Complete |
| Communication | Slack, Gmail | Common operations |
| Database | Postgres, MySQL | CRUD operations |
| Transform | Set, Code | All modes |
| Conditional | IF, Switch | All operator types |
| AI | OpenAI | Chat completion |
| Schedule | Schedule Trigger | All modes |
## Related Documentation
- **n8n-mcp MCP Server**: Provides discovery tools
- **n8n Node API**: get_node_essentials, get_property_dependencies, get_node_info
- **n8n Schema**: displayOptions mechanism, property definitions
## Version History
- **v1.0** (2025-10-20): Initial implementation
- SKILL.md with configuration workflow
- DEPENDENCIES.md with displayOptions deep dive
- OPERATION_PATTERNS.md with 20+ node patterns
- 4 evaluation scenarios
## Author
Conceived by Romuald Członkowski - [www.aiadvisors.pl/en](https://www.aiadvisors.pl/en)
Part of the n8n-skills meta-skill collection.

View File

@@ -0,0 +1,785 @@
---
name: n8n-node-configuration
description: Operation-aware node configuration guidance. Use when configuring nodes, understanding property dependencies, determining required fields, choosing between get_node detail levels, or learning common configuration patterns by node type.
---
# n8n Node Configuration
Expert guidance for operation-aware node configuration with property dependencies.
---
## Configuration Philosophy
**Progressive disclosure**: Start minimal, add complexity as needed
Configuration best practices:
- `get_node` with `detail: "standard"` is the most used discovery pattern
- 56 seconds average between configuration edits
- Covers 95% of use cases with 1-2K tokens response
**Key insight**: Most configurations need only standard detail, not full schema!
---
## Core Concepts
### 1. Operation-Aware Configuration
**Not all fields are always required** - it depends on operation!
**Example**: Slack node
```javascript
// For operation='post'
{
"resource": "message",
"operation": "post",
"channel": "#general", // Required for post
"text": "Hello!" // Required for post
}
// For operation='update'
{
"resource": "message",
"operation": "update",
"messageId": "123", // Required for update (different!)
"text": "Updated!" // Required for update
// channel NOT required for update
}
```
**Key**: Resource + operation determine which fields are required!
### 2. Property Dependencies
**Fields appear/disappear based on other field values**
**Example**: HTTP Request node
```javascript
// When method='GET'
{
"method": "GET",
"url": "https://api.example.com"
// sendBody not shown (GET doesn't have body)
}
// When method='POST'
{
"method": "POST",
"url": "https://api.example.com",
"sendBody": true, // Now visible!
"body": { // Required when sendBody=true
"contentType": "json",
"content": {...}
}
}
```
**Mechanism**: displayOptions control field visibility
### 3. Progressive Discovery
**Use the right detail level**:
1. **get_node({detail: "standard"})** - DEFAULT
- Quick overview (~1-2K tokens)
- Required fields + common options
- **Use first** - covers 95% of needs
2. **get_node({mode: "search_properties", propertyQuery: "..."})** (for finding specific fields)
- Find properties by name
- Use when looking for auth, body, headers, etc.
3. **get_node({detail: "full"})** (complete schema)
- All properties (~3-8K tokens)
- Use only when standard detail is insufficient
---
## Configuration Workflow
### Standard Process
```
1. Identify node type and operation
↓
2. Use get_node (standard detail is default)
↓
3. Configure required fields
↓
4. Validate configuration
↓
5. If field unclear → get_node({mode: "search_properties"})
↓
6. Add optional fields as needed
↓
7. Validate again
↓
8. Deploy
```
### Example: Configuring HTTP Request
**Step 1**: Identify what you need
```javascript
// Goal: POST JSON to API
```
**Step 2**: Get node info
```javascript
const info = get_node({
nodeType: "nodes-base.httpRequest"
});
// Returns: method, url, sendBody, body, authentication required/optional
```
**Step 3**: Minimal config
```javascript
{
"method": "POST",
"url": "https://api.example.com/create",
"authentication": "none"
}
```
**Step 4**: Validate
```javascript
validate_node({
nodeType: "nodes-base.httpRequest",
config,
profile: "runtime"
});
// → Error: "sendBody required for POST"
```
**Step 5**: Add required field
```javascript
{
"method": "POST",
"url": "https://api.example.com/create",
"authentication": "none",
"sendBody": true
}
```
**Step 6**: Validate again
```javascript
validate_node({...});
// → Error: "body required when sendBody=true"
```
**Step 7**: Complete configuration
```javascript
{
"method": "POST",
"url": "https://api.example.com/create",
"authentication": "none",
"sendBody": true,
"body": {
"contentType": "json",
"content": {
"name": "={{$json.name}}",
"email": "={{$json.email}}"
}
}
}
```
**Step 8**: Final validation
```javascript
validate_node({...});
// → Valid! ✅
```
---
## get_node Detail Levels
### Standard Detail (DEFAULT - Use This!)
**✅ Starting configuration**
```javascript
get_node({
nodeType: "nodes-base.slack"
});
// detail="standard" is the default
```
**Returns** (~1-2K tokens):
- Required fields
- Common options
- Operation list
- Metadata
**Use**: 95% of configuration needs
### Full Detail (Use Sparingly)
**✅ When standard isn't enough**
```javascript
get_node({
nodeType: "nodes-base.slack",
detail: "full"
});
```
**Returns** (~3-8K tokens):
- Complete schema
- All properties
- All nested options
**Warning**: Large response, use only when standard insufficient
### Search Properties Mode
**✅ Looking for specific field**
```javascript
get_node({
nodeType: "nodes-base.httpRequest",
mode: "search_properties",
propertyQuery: "auth"
});
```
**Use**: Find authentication, headers, body fields, etc.
### Decision Tree
```
┌─────────────────────────────────┐
│ Starting new node config? │
├─────────────────────────────────┤
│ YES → get_node (standard) │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ Standard has what you need? │
├─────────────────────────────────┤
│ YES → Configure with it │
│ NO → Continue │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ Looking for specific field? │
├─────────────────────────────────┤
│ YES → search_properties mode │
│ NO → Continue │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ Still need more details? │
├─────────────────────────────────┤
│ YES → get_node({detail: "full"})│
└─────────────────────────────────┘
```
---
## Property Dependencies Deep Dive
### displayOptions Mechanism
**Fields have visibility rules**:
```javascript
{
"name": "body",
"displayOptions": {
"show": {
"sendBody": [true],
"method": ["POST", "PUT", "PATCH"]
}
}
}
```
**Translation**: "body" field shows when:
- sendBody = true AND
- method = POST, PUT, or PATCH
### Common Dependency Patterns
#### Pattern 1: Boolean Toggle
**Example**: HTTP Request sendBody
```javascript
// sendBody controls body visibility
{
"sendBody": true // → body field appears
}
```
#### Pattern 2: Operation Switch
**Example**: Slack resource/operation
```javascript
// Different operations → different fields
{
"resource": "message",
"operation": "post"
// → Shows: channel, text, attachments, etc.
}
{
"resource": "message",
"operation": "update"
// → Shows: messageId, text (different fields!)
}
```
#### Pattern 3: Type Selection
**Example**: IF node conditions
```javascript
{
"type": "string",
"operation": "contains"
// → Shows: value1, value2
}
{
"type": "boolean",
"operation": "equals"
// → Shows: value1, value2, different operators
}
```
### Finding Property Dependencies
**Use get_node with search_properties mode**:
```javascript
get_node({
nodeType: "nodes-base.httpRequest",
mode: "search_properties",
propertyQuery: "body"
});
// Returns property paths matching "body" with descriptions
```
**Or use full detail for complete schema**:
```javascript
get_node({
nodeType: "nodes-base.httpRequest",
detail: "full"
});
// Returns complete schema with displayOptions rules
```
**Use this when**: Validation fails and you don't understand why field is missing/required
---
## Common Node Patterns
### Pattern 1: Resource/Operation Nodes
**Examples**: Slack, Google Sheets, Airtable
**Structure**:
```javascript
{
"resource": "<entity>", // What type of thing
"operation": "<action>", // What to do with it
// ... operation-specific fields
}
```
**How to configure**:
1. Choose resource
2. Choose operation
3. Use get_node to see operation-specific requirements
4. Configure required fields
### Pattern 2: HTTP-Based Nodes
**Examples**: HTTP Request, Webhook
**Structure**:
```javascript
{
"method": "<HTTP_METHOD>",
"url": "<endpoint>",
"authentication": "<type>",
// ... method-specific fields
}
```
**Dependencies**:
- POST/PUT/PATCH → sendBody available
- sendBody=true → body required
- authentication != "none" → credentials required
### Pattern 3: Database Nodes
**Examples**: Postgres, MySQL, MongoDB
**Structure**:
```javascript
{
"operation": "<query|insert|update|delete>",
// ... operation-specific fields
}
```
**Dependencies**:
- operation="executeQuery" → query required
- operation="insert" → table + values required
- operation="update" → table + values + where required
### Pattern 4: Conditional Logic Nodes
**Examples**: IF, Switch, Merge
**Structure**:
```javascript
{
"conditions": {
"<type>": [
{
"operation": "<operator>",
"value1": "...",
"value2": "..." // Only for binary operators
}
]
}
}
```
**Dependencies**:
- Binary operators (equals, contains, etc.) → value1 + value2
- Unary operators (isEmpty, isNotEmpty) → value1 only + singleValue: true
---
## Operation-Specific Configuration
### Slack Node Examples
#### Post Message
```javascript
{
"resource": "message",
"operation": "post",
"channel": "#general", // Required
"text": "Hello!", // Required
"attachments": [], // Optional
"blocks": [] // Optional
}
```
#### Update Message
```javascript
{
"resource": "message",
"operation": "update",
"messageId": "1234567890", // Required (different from post!)
"text": "Updated!", // Required
"channel": "#general" // Optional (can be inferred)
}
```
#### Create Channel
```javascript
{
"resource": "channel",
"operation": "create",
"name": "new-channel", // Required
"isPrivate": false // Optional
// Note: text NOT required for this operation
}
```
### HTTP Request Node Examples
#### GET Request
```javascript
{
"method": "GET",
"url": "https://api.example.com/users",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "httpHeaderAuth",
"sendQuery": true, // Optional
"queryParameters": { // Shows when sendQuery=true
"parameters": [
{
"name": "limit",
"value": "100"
}
]
}
}
```
#### POST with JSON
```javascript
{
"method": "POST",
"url": "https://api.example.com/users",
"authentication": "none",
"sendBody": true, // Required for POST
"body": { // Required when sendBody=true
"contentType": "json",
"content": {
"name": "John Doe",
"email": "john@example.com"
}
}
}
```
### IF Node Examples
#### String Comparison (Binary)
```javascript
{
"conditions": {
"string": [
{
"value1": "={{$json.status}}",
"operation": "equals",
"value2": "active" // Binary: needs value2
}
]
}
}
```
#### Empty Check (Unary)
```javascript
{
"conditions": {
"string": [
{
"value1": "={{$json.email}}",
"operation": "isEmpty",
// No value2 - unary operator
"singleValue": true // Auto-added by sanitization
}
]
}
}
```
---
## Handling Conditional Requirements
### Example: HTTP Request Body
**Scenario**: body field required, but only sometimes
**Rule**:
```
body is required when:
- sendBody = true AND
- method IN (POST, PUT, PATCH, DELETE)
```
**How to discover**:
```javascript
// Option 1: Read validation error
validate_node({...});
// Error: "body required when sendBody=true"
// Option 2: Search for the property
get_node({
nodeType: "nodes-base.httpRequest",
mode: "search_properties",
propertyQuery: "body"
});
// Shows: body property with displayOptions rules
// Option 3: Try minimal config and iterate
// Start without body, validation will tell you if needed
```
### Example: IF Node singleValue
**Scenario**: singleValue property appears for unary operators
**Rule**:
```
singleValue should be true when:
- operation IN (isEmpty, isNotEmpty, true, false)
```
**Good news**: Auto-sanitization fixes this!
**Manual check**:
```javascript
get_node({
nodeType: "nodes-base.if",
detail: "full"
});
// Shows complete schema with operator-specific rules
```
---
## Configuration Anti-Patterns
### ❌ Don't: Over-configure Upfront
**Bad**:
```javascript
// Adding every possible field
{
"method": "GET",
"url": "...",
"sendQuery": false,
"sendHeaders": false,
"sendBody": false,
"timeout": 10000,
"ignoreResponseCode": false,
// ... 20 more optional fields
}
```
**Good**:
```javascript
// Start minimal
{
"method": "GET",
"url": "...",
"authentication": "none"
}
// Add fields only when needed
```
### ❌ Don't: Skip Validation
**Bad**:
```javascript
// Configure and deploy without validating
const config = {...};
n8n_update_partial_workflow({...}); // YOLO
```
**Good**:
```javascript
// Validate before deploying
const config = {...};
const result = validate_node({...});
if (result.valid) {
n8n_update_partial_workflow({...});
}
```
### ❌ Don't: Ignore Operation Context
**Bad**:
```javascript
// Same config for all Slack operations
{
"resource": "message",
"operation": "post",
"channel": "#general",
"text": "..."
}
// Then switching operation without updating config
{
"resource": "message",
"operation": "update", // Changed
"channel": "#general", // Wrong field for update!
"text": "..."
}
```
**Good**:
```javascript
// Check requirements when changing operation
get_node({
nodeType: "nodes-base.slack"
});
// See what update operation needs (messageId, not channel)
```
---
## Best Practices
### ✅ Do
1. **Start with get_node (standard detail)**
- ~1-2K tokens response
- Covers 95% of configuration needs
- Default detail level
2. **Validate iteratively**
- Configure → Validate → Fix → Repeat
- Average 2-3 iterations is normal
- Read validation errors carefully
3. **Use search_properties mode when stuck**
- If field seems missing, search for it
- Understand what controls field visibility
- `get_node({mode: "search_properties", propertyQuery: "..."})`
4. **Respect operation context**
- Different operations = different requirements
- Always check get_node when changing operation
- Don't assume configs are transferable
5. **Trust auto-sanitization**
- Operator structure fixed automatically
- Don't manually add/remove singleValue
- IF/Switch metadata added on save
### ❌ Don't
1. **Jump to detail="full" immediately**
- Try standard detail first
- Only escalate if needed
- Full schema is 3-8K tokens
2. **Configure blindly**
- Always validate before deploying
- Understand why fields are required
- Use search_properties for conditional fields
3. **Copy configs without understanding**
- Different operations need different fields
- Validate after copying
- Adjust for new context
4. **Manually fix auto-sanitization issues**
- Let auto-sanitization handle operator structure
- Focus on business logic
- Save and let system fix structure
---
## Detailed References
For comprehensive guides on specific topics:
- **[DEPENDENCIES.md](DEPENDENCIES.md)** - Deep dive into property dependencies and displayOptions
- **[OPERATION_PATTERNS.md](OPERATION_PATTERNS.md)** - Common configuration patterns by node type
---
## Summary
**Configuration Strategy**:
1. Start with `get_node` (standard detail is default)
2. Configure required fields for operation
3. Validate configuration
4. Search properties if stuck
5. Iterate until valid (avg 2-3 cycles)
6. Deploy with confidence
**Key Principles**:
- **Operation-aware**: Different operations = different requirements
- **Progressive disclosure**: Start minimal, add as needed
- **Dependency-aware**: Understand field visibility rules
- **Validation-driven**: Let validation guide configuration
**Related Skills**:
- **n8n MCP Tools Expert** - How to use discovery tools correctly
- **n8n Validation Expert** - Interpret validation errors
- **n8n Expression Syntax** - Configure expression fields
- **n8n Workflow Patterns** - Apply patterns with proper configuration

Submodule .opencode/skills/n8n-opencode-skill added at 3d6b40cc63

View File

@@ -0,0 +1,943 @@
# 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 | Warning | ✅ |
---
## 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**
#### 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**
#### 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
#### Example 1: Missing Curly Braces
**Error**:
```json
{
"type": "invalid_expression",
"property": "text",
"message": "Expressions must be wrapped in {{}}",
"current": "$json.name"
}
```
**Broken Configuration**:
```javascript
{
"resource": "message",
"operation": "post",
"channel": "#general",
"text": "$json.name" // ❌ Missing {{}}
}
```
**Fix**:
```javascript
{
"resource": "message",
"operation": "post",
"channel": "#general",
"text": "={{$json.name}}" // ✅ Wrapped in {{}}
}
```
#### 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**
#### 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)
**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**:
```javascript
{
"resource": "message",
"operation": "post",
"channel": "#alerts",
"continueOnFail": true,
"retryOnFail": true,
"maxTries": 3
}
```
#### 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 old API version or deprecated feature
**Severity**: Warning (still works but may stop working in future)
**When to fix**: Always (eventually)
#### Example 1: Old typeVersion
**Warning**:
```json
{
"type": "deprecated",
"property": "typeVersion",
"message": "typeVersion 1 is deprecated for Slack node, use version 2",
"current": 1,
"recommended": 2
}
```
**Fix**:
```javascript
{
"type": "n8n-nodes-base.slack",
"typeVersion": 2, // ✅ Updated
// May need to update configuration for new version
}
```
---
### 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**: IF/Switch operator structure issues
**Severity**: Warning
**Auto-Fix**: ✅ YES - Fixed automatically on workflow save
**Rare** (mostly auto-fixed)
#### Fixed Automatically: 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!
#### Fixed Automatically: 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!
---
## 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_operation({...});
// 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

View File

@@ -0,0 +1,720 @@
# False Positives Guide
When validation warnings are acceptable and how to handle them.
---
## What Are False Positives?
**Definition**: Validation warnings that are technically "issues" but acceptable in your specific use case.
**Key insight**: Not all warnings need to be fixed!
Many warnings are context-dependent:
- ~40% of warnings are acceptable in specific use cases
- Using `ai-friendly` profile reduces false positives by 60%
---
## Philosophy
### ✅ Good Practice
```
1. Run validation with 'runtime' profile
2. Fix all ERRORS
3. Review each WARNING
4. Decide if acceptable for your use case
5. Document why you accepted it
6. Deploy with confidence
```
### ❌ Bad Practice
```
1. Ignore all warnings blindly
2. Use 'minimal' profile to avoid warnings
3. Deploy without understanding risks
```
---
## Common False Positives
### 1. Missing Error Handling
**Warning**:
```json
{
"type": "best_practice",
"message": "No error handling configured",
"suggestion": "Add continueOnFail: true and retryOnFail: true"
}
```
#### When Acceptable
**✅ Development/Testing Workflows**
```javascript
// Testing workflow - failures are obvious
{
"name": "Test Slack Integration",
"nodes": [{
"type": "n8n-nodes-base.slack",
"parameters": {
"resource": "message",
"operation": "post",
"channel": "#test"
// No error handling - OK for testing
}
}]
}
```
**Reasoning**: You WANT to see failures during testing.
**✅ Non-Critical Notifications**
```javascript
// Nice-to-have notification
{
"name": "Optional Slack Notification",
"parameters": {
"channel": "#general",
"text": "FYI: Process completed"
// If this fails, no big deal
}
}
```
**Reasoning**: Notification failure doesn't affect core functionality.
**✅ Manual Trigger Workflows**
```javascript
// Manual workflow - user is watching
{
"nodes": [{
"type": "n8n-nodes-base.webhook",
"parameters": {
"path": "manual-test"
// No error handling - user will retry manually
}
}]
}
```
**Reasoning**: User is present to see and handle errors.
#### When to Fix
**❌ Production Automation**
```javascript
// BAD: Critical workflow without error handling
{
"name": "Process Customer Orders",
"nodes": [{
"type": "n8n-nodes-base.postgres",
"parameters": {
"query": "INSERT INTO orders..."
// ❌ Should have error handling!
}
}]
}
```
**Fix**:
```javascript
{
"parameters": {
"query": "INSERT INTO orders...",
"continueOnFail": true,
"retryOnFail": true,
"maxTries": 3,
"waitBetweenTries": 1000
}
}
```
**❌ Critical Integrations**
```javascript
// BAD: Payment processing without error handling
{
"name": "Process Payment",
"type": "n8n-nodes-base.stripe"
// ❌ Payment failures MUST be handled!
}
```
---
### 2. No Retry Logic
**Warning**:
```json
{
"type": "best_practice",
"message": "External API calls should retry on failure",
"suggestion": "Add retryOnFail: true with exponential backoff"
}
```
#### When Acceptable
**✅ APIs with Built-in Retry**
```javascript
// Stripe has its own retry mechanism
{
"type": "n8n-nodes-base.stripe",
"parameters": {
"resource": "charge",
"operation": "create"
// Stripe SDK retries automatically
}
}
```
**✅ Idempotent Operations**
```javascript
// GET request - safe to retry manually if needed
{
"method": "GET",
"url": "https://api.example.com/status"
// Read-only, no side effects
}
```
**✅ Local/Internal Services**
```javascript
// Internal API with high reliability
{
"url": "http://localhost:3000/process"
// Local service, failures are rare and obvious
}
```
#### When to Fix
**❌ Flaky External APIs**
```javascript
// BAD: Known unreliable API without retries
{
"url": "https://unreliable-api.com/data"
// ❌ Should retry!
}
// GOOD:
{
"url": "https://unreliable-api.com/data",
"retryOnFail": true,
"maxTries": 3,
"waitBetweenTries": 2000
}
```
**❌ Non-Idempotent Operations**
```javascript
// BAD: POST without retry - may lose data
{
"method": "POST",
"url": "https://api.example.com/create"
// ❌ Could timeout and lose data
}
```
---
### 3. Missing Rate Limiting
**Warning**:
```json
{
"type": "best_practice",
"message": "API may have rate limits",
"suggestion": "Add rate limiting or batch requests"
}
```
#### When Acceptable
**✅ Internal APIs**
```javascript
// Internal microservice - no rate limits
{
"url": "http://internal-api/process"
// Company controls both ends
}
```
**✅ Low-Volume Workflows**
```javascript
// Runs once per day
{
"trigger": {
"type": "n8n-nodes-base.cron",
"parameters": {
"mode": "everyDay",
"hour": 9
}
},
"nodes": [{
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"url": "https://api.example.com/daily-report"
// Once per day = no rate limit concerns
}
}]
}
```
**✅ APIs with Server-Side Limits**
```javascript
// API returns 429 and n8n handles it
{
"url": "https://api.example.com/data",
"options": {
"response": {
"response": {
"neverError": false // Will error on 429
}
}
},
"retryOnFail": true // Retry on 429
}
```
#### When to Fix
**❌ High-Volume Public APIs**
```javascript
// BAD: Loop hitting rate-limited API
{
"nodes": [{
"type": "n8n-nodes-base.splitInBatches",
"parameters": {
"batchSize": 100
}
}, {
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"url": "https://api.github.com/..."
// ❌ GitHub has strict rate limits!
}
}]
}
// GOOD: Add rate limiting
{
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"url": "https://api.github.com/...",
"options": {
"batching": {
"batch": {
"batchSize": 10,
"batchInterval": 1000 // 1 second between batches
}
}
}
}
}
```
---
### 4. Unbounded Database Queries
**Warning**:
```json
{
"type": "performance",
"message": "SELECT without LIMIT can return massive datasets",
"suggestion": "Add LIMIT clause or use pagination"
}
```
#### When Acceptable
**✅ Small Known Datasets**
```javascript
// Config table with ~10 rows
{
"query": "SELECT * FROM app_config"
// Known to be small, no LIMIT needed
}
```
**✅ Aggregation Queries**
```javascript
// COUNT/SUM operations
{
"query": "SELECT COUNT(*) as total FROM users WHERE active = true"
// Aggregation, not returning rows
}
```
**✅ Development/Testing**
```javascript
// Testing with small dataset
{
"query": "SELECT * FROM test_users"
// Test database has 5 rows
}
```
#### When to Fix
**❌ Production Queries on Large Tables**
```javascript
// BAD: User table could have millions of rows
{
"query": "SELECT * FROM users"
// ❌ Could return millions of rows!
}
// GOOD: Add LIMIT
{
"query": "SELECT * FROM users LIMIT 1000"
}
// BETTER: Use pagination
{
"query": "SELECT * FROM users WHERE id > {{$json.lastId}} LIMIT 1000"
}
```
---
### 5. Missing Input Validation
**Warning**:
```json
{
"type": "best_practice",
"message": "Webhook doesn't validate input data",
"suggestion": "Add IF node to validate required fields"
}
```
#### When Acceptable
**✅ Internal Webhooks**
```javascript
// Webhook from your own backend
{
"type": "n8n-nodes-base.webhook",
"parameters": {
"path": "internal-trigger"
// Your backend already validates
}
}
```
**✅ Trusted Sources**
```javascript
// Webhook from Stripe (cryptographically signed)
{
"type": "n8n-nodes-base.webhook",
"parameters": {
"path": "stripe-webhook",
"authentication": "headerAuth"
// Stripe signature validates authenticity
}
}
```
#### When to Fix
**❌ Public Webhooks**
```javascript
// BAD: Public webhook without validation
{
"type": "n8n-nodes-base.webhook",
"parameters": {
"path": "public-form-submit"
// ❌ Anyone can send anything!
}
}
// GOOD: Add validation
{
"nodes": [
{
"name": "Webhook",
"type": "n8n-nodes-base.webhook"
},
{
"name": "Validate Input",
"type": "n8n-nodes-base.if",
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{$json.body.email}}",
"operation": "isNotEmpty"
},
{
"value1": "={{$json.body.email}}",
"operation": "regex",
"value2": "^[^@]+@[^@]+\\.[^@]+$"
}
]
}
}
}
]
}
```
---
### 6. Hardcoded Credentials
**Warning**:
```json
{
"type": "security",
"message": "Credentials should not be hardcoded",
"suggestion": "Use n8n credential system"
}
```
#### When Acceptable
**✅ Public APIs (No Auth)**
```javascript
// Truly public API with no secrets
{
"url": "https://api.ipify.org"
// No credentials needed
}
```
**✅ Demo/Example Workflows**
```javascript
// Example workflow in documentation
{
"url": "https://example.com/api",
"headers": {
"Authorization": "Bearer DEMO_TOKEN"
}
// Clearly marked as example
}
```
#### When to Fix (Always!)
**❌ Real Credentials**
```javascript
// BAD: Real API key in workflow
{
"headers": {
"Authorization": "Bearer sk_live_abc123..."
}
// ❌ NEVER hardcode real credentials!
}
// GOOD: Use credentials system
{
"authentication": "headerAuth",
"credentials": {
"headerAuth": {
"id": "credential-id",
"name": "My API Key"
}
}
}
```
---
## Validation Profile Strategies
### Strategy 1: Progressive Strictness
**Development**:
```javascript
validate_node({
nodeType: "nodes-base.slack",
config,
profile: "ai-friendly" // Fewer warnings during development
})
```
**Pre-Production**:
```javascript
validate_node({
nodeType: "nodes-base.slack",
config,
profile: "runtime" // Balanced validation
})
```
**Production Deployment**:
```javascript
validate_node({
nodeType: "nodes-base.slack",
config,
profile: "strict" // All warnings, review each one
})
```
### Strategy 2: Profile by Workflow Type
**Quick Automations**:
- Profile: `ai-friendly`
- Accept: Most warnings
- Fix: Only errors + security warnings
**Business-Critical Workflows**:
- Profile: `strict`
- Accept: Very few warnings
- Fix: Everything possible
**Integration Testing**:
- Profile: `minimal`
- Accept: All warnings (just testing connections)
- Fix: Only errors that prevent execution
---
## Decision Framework
### Should I Fix This Warning?
```
┌─────────────────────────────────┐
│ Is it a SECURITY warning? │
├─────────────────────────────────┤
│ YES → Always fix │
│ NO → Continue │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ Is this a production workflow? │
├─────────────────────────────────┤
│ YES → Continue │
│ NO → Probably acceptable │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ Does it handle critical data? │
├─────────────────────────────────┤
│ YES → Fix the warning │
│ NO → Continue │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ Is there a known workaround? │
├─────────────────────────────────┤
│ YES → Acceptable if documented │
│ NO → Fix the warning │
└─────────────────────────────────┘
```
---
## Documentation Template
When accepting a warning, document why:
```javascript
// workflows/customer-notifications.json
{
"nodes": [{
"name": "Send Slack Notification",
"type": "n8n-nodes-base.slack",
"parameters": {
"channel": "#notifications"
// ACCEPTED WARNING: No error handling
// Reason: Non-critical notification, failures are acceptable
// Reviewed: 2025-10-20
// Reviewer: Engineering Team
}
}]
}
```
---
## Known n8n Issues
### Issue #304: IF Node Metadata Warning
**Warning**:
```json
{
"type": "metadata_incomplete",
"message": "IF node missing conditions.options metadata",
"node": "IF"
}
```
**Status**: False positive for IF v2.2+
**Why it occurs**: Auto-sanitization adds metadata, but validation runs before sanitization
**What to do**: Ignore - metadata is added on save
### Issue #306: Switch Branch Count
**Warning**:
```json
{
"type": "configuration_mismatch",
"message": "Switch has 3 rules but 4 output connections",
"node": "Switch"
}
```
**Status**: False positive when using "fallback" mode
**Why it occurs**: Fallback creates extra output
**What to do**: Ignore if using fallback intentionally
### Issue #338: Credential Validation in Test Mode
**Warning**:
```json
{
"type": "credentials_invalid",
"message": "Cannot validate credentials without execution context"
}
```
**Status**: False positive during static validation
**Why it occurs**: Credentials validated at runtime, not build time
**What to do**: Ignore - credentials are validated when workflow runs
---
## Summary
### Always Fix
- ❌ Security warnings
- ❌ Hardcoded credentials
- ❌ SQL injection risks
- ❌ Production workflow errors
### Usually Fix
- ⚠️ Error handling (production)
- ⚠️ Retry logic (external APIs)
- ⚠️ Input validation (public webhooks)
- ⚠️ Rate limiting (high volume)
### Often Acceptable
- ✅ Error handling (dev/test)
- ✅ Retry logic (internal APIs)
- ✅ Rate limiting (low volume)
- ✅ Query limits (small datasets)
### Always Acceptable
- ✅ Known n8n issues (#304, #306, #338)
- ✅ Auto-sanitization warnings
- ✅ Metadata completeness (auto-fixed)
**Golden Rule**: If you accept a warning, document WHY.
**Related Files**:
- **[SKILL.md](SKILL.md)** - Main validation guide
- **[ERROR_CATALOG.md](ERROR_CATALOG.md)** - Error types and fixes

View File

@@ -0,0 +1,290 @@
# n8n Validation Expert
Expert guidance for interpreting and fixing n8n validation errors.
## Overview
**Skill Name**: n8n Validation Expert
**Priority**: Medium
**Purpose**: Interpret validation errors and guide systematic fixing through the validation loop
## The Problem This Solves
Validation errors are common:
- Validation often requires iteration (79% lead to feedback loops)
- **7,841 validate → fix cycles** (avg 23s thinking + 58s fixing)
- **2-3 iterations** average to achieve valid configuration
**Key insight**: Validation is an iterative process, not a one-shot fix!
## What This Skill Teaches
### Core Concepts
1. **Error Severity Levels**
- Errors (must fix) - Block execution
- Warnings (should fix) - Don't block but indicate issues
- Suggestions (optional) - Nice-to-have improvements
2. **The Validation Loop**
- Configure → Validate → Read errors → Fix → Validate again
- Average 2-3 iterations to success
- 23 seconds thinking + 58 seconds fixing per cycle
3. **Validation Profiles**
- `minimal` - Quick checks, most permissive
- `runtime` - Recommended for most use cases
- `ai-friendly` - Reduces false positives for AI workflows
- `strict` - Maximum safety, many warnings
4. **Auto-Sanitization System**
- Automatically fixes operator structure issues
- Runs on every workflow save
- Fixes binary/unary operator problems
- Adds IF/Switch metadata
5. **False Positives**
- Not all warnings need fixing
- 40% of warnings are acceptable in context
- Use `ai-friendly` profile to reduce by 60%
- Document accepted warnings
## File Structure
```
n8n-validation-expert/
├── SKILL.md (690 lines)
│ Core validation concepts and workflow
│ - Validation philosophy
│ - Error severity levels
│ - The validation loop pattern
│ - Validation profiles
│ - Common error types
│ - Auto-sanitization system
│ - Workflow validation
│ - Recovery strategies
│ - Best practices
│
├── ERROR_CATALOG.md (865 lines)
│ Complete error reference with examples
│ - 9 error types with real examples
│ - missing_required (45% of errors)
│ - invalid_value (28%)
│ - type_mismatch (12%)
│ - invalid_expression (8%)
│ - invalid_reference (5%)
│ - operator_structure (2%, auto-fixed)
│ - Recovery patterns
│ - Summary with frequencies
│
├── FALSE_POSITIVES.md (669 lines)
│ When warnings are acceptable
│ - Philosophy of warning acceptance
│ - 6 common false positive types
│ - When acceptable vs when to fix
│ - Validation profile strategies
│ - Decision framework
│ - Documentation template
│ - Known n8n issues (#304, #306, #338)
│
└── README.md (this file)
Skill metadata and statistics
```
**Total**: ~2,224 lines across 4 files
## Common Error Types
| Error Type | Priority | Auto-Fix | Severity |
|---|---|---|---|
| missing_required | Highest | ❌ | Error |
| invalid_value | High | ❌ | Error |
| type_mismatch | Medium | ❌ | Error |
| invalid_expression | Medium | ❌ | Error |
| invalid_reference | Low | ❌ | Error |
| operator_structure | Low | ✅ | Warning |
## Key Insights
### 1. Validation is Iterative
Don't expect to get it right on the first try. Multiple validation cycles (typically 2-3) are normal and expected!
### 2. False Positives Exist
Many validation warnings are acceptable in production workflows. This skill helps you recognize which ones to address vs. which to ignore.
### 3. Auto-Sanitization Works
Certain error types (like operator structure issues) are automatically fixed by n8n. Don't waste time manually fixing these!
### 4. Profile Matters
- `ai-friendly` reduces false positives by 60%
- `runtime` is the sweet spot for most use cases
- `strict` has value pre-production but is noisy
### 5. Error Messages Help
Validation errors include fix guidance - read them carefully!
## Usage Examples
### Example 1: Basic Validation Loop
```javascript
// Iteration 1
let config = {
resource: "channel",
operation: "create"
};
const result1 = validate_node_operation({
nodeType: "nodes-base.slack",
config,
profile: "runtime"
});
// → Error: Missing "name"
// Iteration 2
config.name = "general";
const result2 = validate_node_operation({...});
// → Valid! ✅
```
### Example 2: Handling False Positives
```javascript
// Run validation
const result = validate_node_operation({
nodeType: "nodes-base.slack",
config,
profile: "runtime"
});
// Fix errors (must fix)
if (!result.valid) {
result.errors.forEach(error => {
console.log(`MUST FIX: ${error.message}`);
});
}
// Review warnings (context-dependent)
result.warnings.forEach(warning => {
if (warning.type === 'best_practice' && isDevWorkflow) {
console.log(`ACCEPTABLE: ${warning.message}`);
} else {
console.log(`SHOULD FIX: ${warning.message}`);
}
});
```
### Example 3: Using Auto-Fix
```javascript
// Check what can be auto-fixed
const preview = n8n_autofix_workflow({
id: "workflow-id",
applyFixes: false // Preview mode
});
console.log(`Can auto-fix: ${preview.fixCount} issues`);
// Apply fixes
if (preview.fixCount > 0) {
n8n_autofix_workflow({
id: "workflow-id",
applyFixes: true
});
}
```
## When This Skill Activates
**Trigger phrases**:
- "validation error"
- "validation failing"
- "what does this error mean"
- "false positive"
- "validation loop"
- "operator structure"
- "validation profile"
**Common scenarios**:
- Encountering validation errors
- Stuck in validation feedback loops
- Wondering if warnings need fixing
- Choosing the right validation profile
- Understanding auto-sanitization
## Integration with Other Skills
### Works With:
- **n8n MCP Tools Expert** - How to use validation tools correctly
- **n8n Expression Syntax** - Fix invalid_expression errors
- **n8n Node Configuration** - Understand required fields
- **n8n Workflow Patterns** - Validate pattern implementations
### Complementary:
- Use MCP Tools Expert to call validation tools
- Use Expression Syntax to fix expression errors
- Use Node Configuration to understand dependencies
- Use Workflow Patterns to validate structure
## Testing
**Evaluations**: 4 test scenarios
1. **eval-001-missing-required-field.json**
- Tests error interpretation
- Guides to get_node_essentials
- References ERROR_CATALOG.md
2. **eval-002-false-positive.json**
- Tests warning vs error distinction
- Explains false positives
- References FALSE_POSITIVES.md
- Suggests ai-friendly profile
3. **eval-003-auto-sanitization.json**
- Tests auto-sanitization understanding
- Explains operator structure fixes
- Advises trusting auto-fix
4. **eval-004-validation-loop.json**
- Tests iterative validation process
- Explains 2-3 iteration pattern
- Provides systematic approach
## Success Metrics
**Before this skill**:
- Users confused by validation errors
- Multiple failed attempts to fix
- Frustration with "validation loops"
- Fixing issues that auto-fix handles
- Fixing all warnings unnecessarily
**After this skill**:
- Systematic error resolution
- Understanding of iteration process
- Recognition of false positives
- Trust in auto-sanitization
- Context-aware warning handling
- 94% success within 3 iterations
## Related Documentation
- **n8n-mcp MCP Server**: Provides validation tools
- **n8n Validation API**: validate_node_operation, validate_workflow, n8n_autofix_workflow
- **n8n Issues**: #304 (IF metadata), #306 (Switch branches), #338 (credentials)
## Version History
- **v1.0** (2025-10-20): Initial implementation
- SKILL.md with core concepts
- ERROR_CATALOG.md with 9 error types
- FALSE_POSITIVES.md with 6 false positive patterns
- 4 evaluation scenarios
## Author
Conceived by Romuald Członkowski - [www.aiadvisors.pl/en](https://www.aiadvisors.pl/en)
Part of the n8n-skills meta-skill collection.

View File

@@ -0,0 +1,689 @@
---
name: n8n-validation-expert
description: Interpret validation errors and guide fixing them. Use when encountering validation errors, validation warnings, false positives, operator structure issues, or need help understanding validation results. Also use when asking about validation profiles, error types, or the validation loop process.
---
# n8n Validation Expert
Expert guide for interpreting and fixing n8n validation errors.
---
## Validation Philosophy
**Validate early, validate often**
Validation is typically iterative:
- Expect validation feedback loops
- Usually 2-3 validate → fix cycles
- Average: 23s thinking about errors, 58s fixing them
**Key insight**: Validation is an iterative process, not one-shot!
---
## Error Severity Levels
### 1. Errors (Must Fix)
**Blocks workflow execution** - Must be resolved before activation
**Types**:
- `missing_required` - Required field not provided
- `invalid_value` - Value doesn't match allowed options
- `type_mismatch` - Wrong data type (string instead of number)
- `invalid_reference` - Referenced node doesn't exist
- `invalid_expression` - Expression syntax error
**Example**:
```json
{
"type": "missing_required",
"property": "channel",
"message": "Channel name is required",
"fix": "Provide a channel name (lowercase, no spaces, 1-80 characters)"
}
```
### 2. Warnings (Should Fix)
**Doesn't block execution** - Workflow can be activated but may have issues
**Types**:
- `best_practice` - Recommended but not required
- `deprecated` - Using old API/feature
- `performance` - Potential performance issue
**Example**:
```json
{
"type": "best_practice",
"property": "errorHandling",
"message": "Slack API can have rate limits",
"suggestion": "Add onError: 'continueRegularOutput' with retryOnFail"
}
```
### 3. Suggestions (Optional)
**Nice to have** - Improvements that could enhance workflow
**Types**:
- `optimization` - Could be more efficient
- `alternative` - Better way to achieve same result
---
## The Validation Loop
### Pattern from Telemetry
**7,841 occurrences** of this pattern:
```
1. Configure node
↓
2. validate_node (23 seconds thinking about errors)
↓
3. Read error messages carefully
↓
4. Fix errors
↓
5. validate_node again (58 seconds fixing)
↓
6. Repeat until valid (usually 2-3 iterations)
```
### Example
```javascript
// Iteration 1
let config = {
resource: "channel",
operation: "create"
};
const result1 = validate_node({
nodeType: "nodes-base.slack",
config,
profile: "runtime"
});
// → Error: Missing "name"
// ⏱️ 23 seconds thinking...
// Iteration 2
config.name = "general";
const result2 = validate_node({
nodeType: "nodes-base.slack",
config,
profile: "runtime"
});
// → Error: Missing "text"
// ⏱️ 58 seconds fixing...
// Iteration 3
config.text = "Hello!";
const result3 = validate_node({
nodeType: "nodes-base.slack",
config,
profile: "runtime"
});
// → Valid! ✅
```
**This is normal!** Don't be discouraged by multiple iterations.
---
## Validation Profiles
Choose the right profile for your stage:
### minimal
**Use when**: Quick checks during editing
**Validates**:
- Only required fields
- Basic structure
**Pros**: Fastest, most permissive
**Cons**: May miss issues
### runtime (RECOMMENDED)
**Use when**: Pre-deployment validation
**Validates**:
- Required fields
- Value types
- Allowed values
- Basic dependencies
**Pros**: Balanced, catches real errors
**Cons**: Some edge cases missed
**This is the recommended profile for most use cases**
### ai-friendly
**Use when**: AI-generated configurations
**Validates**:
- Same as runtime
- Reduces false positives
- More tolerant of minor issues
**Pros**: Less noisy for AI workflows
**Cons**: May allow some questionable configs
### strict
**Use when**: Production deployment, critical workflows
**Validates**:
- Everything
- Best practices
- Performance concerns
- Security issues
**Pros**: Maximum safety
**Cons**: Many warnings, some false positives
---
## Common Error Types
### 1. missing_required
**What it means**: A required field is not provided
**How to fix**:
1. Use `get_node` to see required fields
2. Add the missing field to your configuration
3. Provide an appropriate value
**Example**:
```javascript
// Error
{
"type": "missing_required",
"property": "channel",
"message": "Channel name is required"
}
// Fix
config.channel = "#general";
```
### 2. invalid_value
**What it means**: Value doesn't match allowed options
**How to fix**:
1. Check error message for allowed values
2. Use `get_node` to see options
3. Update to a valid value
**Example**:
```javascript
// Error
{
"type": "invalid_value",
"property": "operation",
"message": "Operation must be one of: post, update, delete",
"current": "send"
}
// Fix
config.operation = "post"; // Use valid operation
```
### 3. type_mismatch
**What it means**: Wrong data type for field
**How to fix**:
1. Check expected type in error message
2. Convert value to correct type
**Example**:
```javascript
// Error
{
"type": "type_mismatch",
"property": "limit",
"message": "Expected number, got string",
"current": "100"
}
// Fix
config.limit = 100; // Number, not string
```
### 4. invalid_expression
**What it means**: Expression syntax error
**How to fix**:
1. Use n8n Expression Syntax skill
2. Check for missing `{{}}` or typos
3. Verify node/field references
**Example**:
```javascript
// Error
{
"type": "invalid_expression",
"property": "text",
"message": "Invalid expression: $json.name",
"current": "$json.name"
}
// Fix
config.text = "={{$json.name}}"; // Add {{}}
```
### 5. invalid_reference
**What it means**: Referenced node doesn't exist
**How to fix**:
1. Check node name spelling
2. Verify node exists in workflow
3. Update reference to correct name
**Example**:
```javascript
// Error
{
"type": "invalid_reference",
"property": "expression",
"message": "Node 'HTTP Requets' does not exist",
"current": "={{$node['HTTP Requets'].json.data}}"
}
// Fix - correct typo
config.expression = "={{$node['HTTP Request'].json.data}}";
```
---
## Auto-Sanitization System
### What It Does
**Automatically fixes common operator structure issues** on ANY workflow update
**Runs when**:
- `n8n_create_workflow`
- `n8n_update_partial_workflow`
- Any workflow save operation
### What It Fixes
#### 1. Binary Operators (Two Values)
**Operators**: equals, notEquals, contains, notContains, greaterThan, lessThan, startsWith, endsWith
**Fix**: Removes `singleValue` property (binary operators compare two values)
**Before**:
```javascript
{
"type": "boolean",
"operation": "equals",
"singleValue": true // ❌ Wrong!
}
```
**After** (automatic):
```javascript
{
"type": "boolean",
"operation": "equals"
// singleValue removed ✅
}
```
#### 2. Unary Operators (One Value)
**Operators**: isEmpty, isNotEmpty, true, false
**Fix**: Adds `singleValue: true` (unary operators check single value)
**Before**:
```javascript
{
"type": "boolean",
"operation": "isEmpty"
// Missing singleValue ❌
}
```
**After** (automatic):
```javascript
{
"type": "boolean",
"operation": "isEmpty",
"singleValue": true // ✅ Added
}
```
#### 3. IF/Switch Metadata
**Fix**: Adds complete `conditions.options` metadata for IF v2.2+ and Switch v3.2+
### What It CANNOT Fix
#### 1. Broken Connections
References to non-existent nodes
**Solution**: Use `cleanStaleConnections` operation in `n8n_update_partial_workflow`
#### 2. Branch Count Mismatches
3 Switch rules but only 2 output connections
**Solution**: Add missing connections or remove extra rules
#### 3. Paradoxical Corrupt States
API returns corrupt data but rejects updates
**Solution**: May require manual database intervention
---
## False Positives
### What Are They?
Validation warnings that are technically "wrong" but acceptable in your use case
### Common False Positives
#### 1. "Missing error handling"
**Warning**: No error handling configured
**When acceptable**:
- Simple workflows where failures are obvious
- Testing/development workflows
- Non-critical notifications
**When to fix**: Production workflows handling important data
#### 2. "No retry logic"
**Warning**: Node doesn't retry on failure
**When acceptable**:
- APIs with their own retry logic
- Idempotent operations
- Manual trigger workflows
**When to fix**: Flaky external services, production automation
#### 3. "Missing rate limiting"
**Warning**: No rate limiting for API calls
**When acceptable**:
- Internal APIs with no limits
- Low-volume workflows
- APIs with server-side rate limiting
**When to fix**: Public APIs, high-volume workflows
#### 4. "Unbounded query"
**Warning**: SELECT without LIMIT
**When acceptable**:
- Small known datasets
- Aggregation queries
- Development/testing
**When to fix**: Production queries on large tables
### Reducing False Positives
**Use `ai-friendly` profile**:
```javascript
validate_node({
nodeType: "nodes-base.slack",
config: {...},
profile: "ai-friendly" // Fewer false positives
})
```
---
## Validation Result Structure
### Complete Response
```javascript
{
"valid": false,
"errors": [
{
"type": "missing_required",
"property": "channel",
"message": "Channel name is required",
"fix": "Provide a channel name (lowercase, no spaces)"
}
],
"warnings": [
{
"type": "best_practice",
"property": "errorHandling",
"message": "Slack API can have rate limits",
"suggestion": "Add onError: 'continueRegularOutput'"
}
],
"suggestions": [
{
"type": "optimization",
"message": "Consider using batch operations for multiple messages"
}
],
"summary": {
"hasErrors": true,
"errorCount": 1,
"warningCount": 1,
"suggestionCount": 1
}
}
```
### How to Read It
#### 1. Check `valid` field
```javascript
if (result.valid) {
// ✅ Configuration is valid
} else {
// ❌ Has errors - must fix before deployment
}
```
#### 2. Fix errors first
```javascript
result.errors.forEach(error => {
console.log(`Error in ${error.property}: ${error.message}`);
console.log(`Fix: ${error.fix}`);
});
```
#### 3. Review warnings
```javascript
result.warnings.forEach(warning => {
console.log(`Warning: ${warning.message}`);
console.log(`Suggestion: ${warning.suggestion}`);
// Decide if you need to address this
});
```
#### 4. Consider suggestions
```javascript
// Optional improvements
// Not required but may enhance workflow
```
---
## Workflow Validation
### validate_workflow (Structure)
**Validates entire workflow**, not just individual nodes
**Checks**:
1. **Node configurations** - Each node valid
2. **Connections** - No broken references
3. **Expressions** - Syntax and references valid
4. **Flow** - Logical workflow structure
**Example**:
```javascript
validate_workflow({
workflow: {
nodes: [...],
connections: {...}
},
options: {
validateNodes: true,
validateConnections: true,
validateExpressions: true,
profile: "runtime"
}
})
```
### Common Workflow Errors
#### 1. Broken Connections
```json
{
"error": "Connection from 'Transform' to 'NonExistent' - target node not found"
}
```
**Fix**: Remove stale connection or create missing node
#### 2. Circular Dependencies
```json
{
"error": "Circular dependency detected: Node A → Node B → Node A"
}
```
**Fix**: Restructure workflow to remove loop
#### 3. Multiple Start Nodes
```json
{
"warning": "Multiple trigger nodes found - only one will execute"
}
```
**Fix**: Remove extra triggers or split into separate workflows
#### 4. Disconnected Nodes
```json
{
"warning": "Node 'Transform' is not connected to workflow flow"
}
```
**Fix**: Connect node or remove if unused
---
## Recovery Strategies
### Strategy 1: Start Fresh
**When**: Configuration is severely broken
**Steps**:
1. Note required fields from `get_node`
2. Create minimal valid configuration
3. Add features incrementally
4. Validate after each addition
### Strategy 2: Binary Search
**When**: Workflow validates but executes incorrectly
**Steps**:
1. Remove half the nodes
2. Validate and test
3. If works: problem is in removed nodes
4. If fails: problem is in remaining nodes
5. Repeat until problem isolated
### Strategy 3: Clean Stale Connections
**When**: "Node not found" errors
**Steps**:
```javascript
n8n_update_partial_workflow({
id: "workflow-id",
operations: [{
type: "cleanStaleConnections"
}]
})
```
### Strategy 4: Use Auto-fix
**When**: Operator structure errors
**Steps**:
```javascript
n8n_autofix_workflow({
id: "workflow-id",
applyFixes: false // Preview first
})
// Review fixes, then apply
n8n_autofix_workflow({
id: "workflow-id",
applyFixes: true
})
```
---
## Best Practices
### ✅ Do
- Validate after every significant change
- Read error messages completely
- Fix errors iteratively (one at a time)
- Use `runtime` profile for pre-deployment
- Check `valid` field before assuming success
- Trust auto-sanitization for operator issues
- Use `get_node` when unclear about requirements
- Document false positives you accept
### ❌ Don't
- Skip validation before activation
- Try to fix all errors at once
- Ignore error messages
- Use `strict` profile during development (too noisy)
- Assume validation passed (always check result)
- Manually fix auto-sanitization issues
- Deploy with unresolved errors
- Ignore all warnings (some are important!)
---
## Detailed Guides
For comprehensive error catalogs and false positive examples:
- **[ERROR_CATALOG.md](ERROR_CATALOG.md)** - Complete list of error types with examples
- **[FALSE_POSITIVES.md](FALSE_POSITIVES.md)** - When warnings are acceptable
---
## Summary
**Key Points**:
1. **Validation is iterative** (avg 2-3 cycles, 23s + 58s)
2. **Errors must be fixed**, warnings are optional
3. **Auto-sanitization** fixes operator structures automatically
4. **Use runtime profile** for balanced validation
5. **False positives exist** - learn to recognize them
6. **Read error messages** - they contain fix guidance
**Validation Process**:
1. Validate → Read errors → Fix → Validate again
2. Repeat until valid (usually 2-3 iterations)
3. Review warnings and decide if acceptable
4. Deploy with confidence
**Related Skills**:
- n8n MCP Tools Expert - Use validation tools correctly
- n8n Expression Syntax - Fix expression errors
- n8n Node Configuration - Understand required fields