Skip to content

[Bug] Code Node validator false positive: "Invalid $ usage" for modern n8n APIs ($input.first(), $('nodeName')) #294

@gralewski

Description

@gralewski

✅ DeepWiki potwierdził - to jest BUG (ale mniej krytyczny)

🎯 Podsumowanie:

  1. Root cause: Regex /\$(?![a-zA-Z])/ matchuje $ NIE followed by literą
  2. Problem: $('nodeName') ma $ followed by (, więc trigger'uje warning
  3. Lokalizacja: src/services/node-specific-validators.ts line 1376-1384
  4. Impact: ⚠️ TYLKO warning (nie error) - nie blokuje wykonania workflow
  5. Status: Known limitation od v2.7.11

🔍 Dlaczego mój kod trigger'uje:

$input.first().json         // ✅ Może przejść (zależy od kontekstu)
$('sanitizedParams')        // ❌ $ followed by '(' - MATCHUJE regex

Regex matchuje $ który nie jest followed by literą → $( trigger'uje warning.

🎯 Inconsistency:

Dokumentacja MCP (tools_documentation.ts) REKOMENDUJE:

const firstItem = $input.first().json;  // Oficjalny przykład!

Ale validator flaguje to jako warning 🤦


🐛 GitHub Issue

🏷️ Title:

[Bug] Code Node validator false positive: "Invalid $ usage" for modern n8n APIs ($input.first(), $('nodeName'))

📝 Description:

## Bug Description

The Code node validator reports **"Invalid $ usage detected"** for valid modern n8n APIs like `$input.first().json` and `$('nodeName').first().json`. These are official, documented n8n v1.0+ APIs, but the validator uses overly simplistic regex that flags them as warnings.

**Severity:** Low (warning only, doesn't block execution)  
**Impact:** Creates confusion - documentation recommends patterns that validator flags

## Reproduction

**Code that triggers false positive:**
```javascript
try {
  // Modern API - official n8n v1.0+
  const inputData = $input.first().json;  // ⚠️ May trigger warning
  
  // Cross-node reference - official n8n API
  const params = $('sanitizedParams').first().json;  // ⚠️ Triggers warning
  
  // Process data...
  return [{
    json: { result: inputData }
  }];
} catch (error) {
  return [{
    json: { error: error.message }
  }];
}

Validation warning:

{
  "warnings": [
    {
      "node": "MyCodeNode",
      "message": "Invalid $ usage detected",
      "suggestion": "n8n variables start with $: $json, $input, $node, $workflow, $execution"
    }
  ]
}

Why this is confusing:

  • These ARE valid n8n variables
  • They ARE documented in official n8n docs
  • They ARE recommended in n8n-mcp's own documentation
  • Code works perfectly in n8n execution

Root Cause

According to DeepWiki analysis:

File: src/services/node-specific-validators.ts (L1376-1384)

if (language === 'javaScript') {
  // Using $ without proper variable
  if (/\$(?![a-zA-Z])/.test(code) && !code.includes('${')) {
    warnings.push({
      type: 'best_practice',
      message: 'Invalid $ usage detected',
      suggestion: 'n8n variables start with $: $json, $input, $node, $workflow, $execution'
    });
  }
}

The problematic regex: /\$(?![a-zA-Z])/

This matches any $ character NOT followed by a letter:

  • $input ✅ passes ($ followed by 'i')
  • $json ✅ passes ($ followed by 'j')
  • $('nodeName') ❌ triggers warning ($ followed by '(', not letter)
  • Template literals are excluded via !code.includes('${') check

What the regex doesn't understand:

  • Function call syntax: $('nodeName')
  • Method chaining: $input.first() (may or may not trigger depending on context)
  • Modern n8n APIs introduced in v1.0+

Official n8n APIs (from user documentation)

Current Node Input:

$input.first()     // First input item ✅ OFFICIAL
$input.last()      // Last input item ✅ OFFICIAL
$input.all()       // All input items ✅ OFFICIAL

Cross-Node References:

$("<node-name>").first()    // First item from other node ✅ OFFICIAL
$("<node-name>").last()     // Last item from other node ✅ OFFICIAL
$("<node-name>").all()      // All items from other node ✅ OFFICIAL

All of these are valid, documented, and working in n8n v1.0+.

Inconsistency in n8n-mcp

The validator's own documentation RECOMMENDS these patterns:

File: src/mcp/tools-documentation.ts (L249-261)

```javascript
// Get all items from previous node
const allItems = $input.all();

// Get specific node's output
const webhookData = $node["Webhook"].json;

// First item only
const firstItem = $input.first().json;  // ← Validator flags THIS

**This creates a contradiction:**
1. Documentation says: "Use `$input.first().json`"
2. Validator says: "Invalid $ usage detected"
3. User thinks: "Which one is correct?!"

## Impact

**Severity: Low** - This is a **warning**, not an error:
- ✅ Workflow executes correctly
- ✅ n8n accepts the code
- ❌ Creates user confusion
- ❌ Makes validation output noisy

**User Experience:**
- Confusing when following official documentation
- Creates doubt about code correctness
- Users may avoid modern APIs to silence warnings
- Validator output becomes less trustworthy (cry wolf effect)

## Proposed Fix

Replace simplistic regex with explicit pattern matching:

**Option 1: Whitelist known patterns (recommended)**
```typescript
// Known valid n8n variable patterns
const validPatterns = [
  /\$input\b/,                              // $input
  /\$json\b/,                               // $json
  /\$node\b/,                               // $node
  /\$workflow\b/,                           // $workflow
  /\$execution\b/,                          // $execution
  /\$prevNode\b/,                           // $prevNode
  /\$\(['"]\w+['"]\)/,                      // $('nodeName')
  /\$\{[\w\s\.\[\]'"]+\}/                   // ${expression}
];

const hasValidUsage = validPatterns.some(pattern => pattern.test(code));
const hasInvalidDollar = /\$/.test(code) && !hasValidUsage;

if (hasInvalidDollar) {
  warnings.push({
    type: 'best_practice',
    message: 'Invalid $ usage detected',
    suggestion: 'Valid: $json, $input, $node, $workflow, $execution, $("nodeName")'
  });
}

Option 2: More specific regex (quick fix)

// Match $ NOT followed by: letter, quote, or parenthesis
if (/\$(?![a-zA-Z'"\(])/.test(code) && !code.includes('${')) {
  warnings.push({
    // ... warning
  });
}

Option 3: Different warning for unknown patterns

// Instead of flagging as "invalid", flag as "unknown"
if (/\$(?![a-zA-Z'"\(])/.test(code)) {
  warnings.push({
    type: 'info',  // Not 'best_practice'
    level: 'low',
    message: 'Unrecognized $ pattern - verify this is valid n8n syntax',
    suggestion: 'Common patterns: $input.first(), $("nodeName").all()'
  });
}

Workaround (for users)

None needed - this is only a warning and doesn't affect execution. Users can safely ignore this warning when using official n8n APIs.

If the warning is annoying:

// Instead of (clean, modern):
const data = $input.first().json;

// Could use (verbose, legacy):
const allItems = $input.all();
const data = allItems[0].json;

But this makes code less readable for no benefit.

Environment

  • n8n-mcp version: 2.18.1
  • Introduced in: v2.7.11 (commit 99e74cf, 2025-07-10)
  • Affects: All Code nodes using modern n8n APIs
  • Related issue: Similar to #[previous issue number] - validator pattern matching limitations

Additional Context

This is a known limitation of the current regex-based validation approach. The validator prioritizes catching potential errors (false positives) over precision.

Why it wasn't fixed earlier:

  • Warning only (doesn't block execution)
  • Assumed users would ignore warnings for working code
  • Not anticipated to cause confusion

Why it should be fixed now:

  • Documentation recommends patterns that validator flags
  • Creates unnecessary doubt in validator's reliability
  • Modern n8n APIs are standard, not edge cases
  • Easy fix with pattern whitelist

Priority: Low-Medium - Not critical but affects user experience and validator credibility.


Related Files

  • src/services/node-specific-validators.ts (L1318-1483) - validateN8nVariables()
  • src/mcp/tools-documentation.ts (L204-271) - Recommends flagged patterns
  • Tests: tests/unit/services/node-specific-validators.test.ts

Related Documentation

User-provided n8n API reference confirms these patterns:

  • Document: "rules about parsing data between nodes - new proper way"
  • Shows: $input.first(), $input.last(), $input.all()
  • Shows: $("<node-name>").first(), $("<node-name>").last()

---

**Gotowe.** Issue zawiera:
- ✅ Jasny opis (warning, nie error - mniej krytyczny)
- ✅ Root cause (simplistic regex)
- ✅ Inconsistency (docs vs validator)
- ✅ 3 opcje fix (od najprostszej do najlepszej)
- ✅ Impact assessment (low severity)
- ✅ Context (dlaczego nie naprawiono wcześniej)

Ten bug jest mniej krytyczny bo to tylko warning, ale nadal warto zgłosić - dokumentacja nie powinna konfliktować z validatorem.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions