<!--
  VENDORED from n8n-builder@d293559 (n8n-validation-expert/FALSE_POSITIVES.md) — DO NOT EDIT HERE.
  Edit the source in ~/Projects/n8n-builder, then re-run:
    node mcp/scripts/sync-n8n-references.mjs --write

  Awesomate platform overrides — where this file conflicts with
  ../platform-notes.md, platform-notes wins:
    - $env is BLOCKED fleet-wide → use {{ $vars.key || 'fallback' }}
    - Task runners are ON → no $helpers in Code nodes; use HTTP Request nodes
    - Webhook payloads live at $json.body
    - saveExecutionProgress must stay false
-->

# False Positives Guide

When n8n warnings are acceptable and how to handle them.

---

## What Are False Positives?

**Definition**: Warnings that are technically "issues" but acceptable - or plain incorrect - in your specific use case.

**Key insight**: Not all warnings need to be fixed!

Many warnings are context-dependent: a large share of them are acceptable in specific use cases, and some are simply wrong about your workflow.

---

## Philosophy

### ✅ Good Practice
```
1. Read every warning in the editor / review output
2. Fix all ERRORS
3. Review each WARNING
4. Decide if acceptable for your use case
5. Document why you accepted it
6. Activate with confidence
```

### ❌ Bad Practice
```
1. Ignore all warnings blindly
2. Skip the review entirely to avoid warnings
3. Activate without understanding risks
```

---

## Structural False Positives

These aren't judgment calls - the warning itself is wrong about your workflow.

### A. Community/Custom Nodes Reported as Unknown

**Warning**:
```
Unknown node type: n8n-nodes-zernio.late
```

**Status**: False positive when the target instance has the community package installed

**Why it occurs**: Community and custom nodes (`CUSTOM.*`, `n8n-nodes-*`) can't be recognized outside the instance that has them - reviewing exported JSON elsewhere flags them as unknown.

**What to do**: Confirm the package is installed on the target instance; if so, ignore. Only treat as an error if the node type is a typo or the package is genuinely missing.

### B. Cycle-Based Polling Flagged as Circular Dependency

**Warning**:
```
Circular dependency detected: Check Status → Wait → Check Status
```

**Status**: False positive for intentional polling loops

**Why it occurs**: Structural review flags any cycle, but loop-back polling (Wait → check status → IF not done → loop back) is a legitimate pattern.

**What to do**: Ignore if the loop has a clear exit condition (IF branch that leaves the loop, max-attempts counter). Fix only if there's no way out of the cycle.

---

## Common Context-Dependent Warnings

### 1. Missing Error Handling

**Warning**:
```
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**:
```
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**:
```
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**:
```
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**:
```
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**:
```
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"
    }
  }
}
```

---

## Review Strictness by Workflow Type

**Quick Automations**:
- Review: required fields + expressions
- Accept: Most warnings
- Fix: Only errors + security warnings

**Business-Critical Workflows**:
- Review: full pass (fields, values, types, expressions, connections, error handling, retries, rate limits)
- Accept: Very few warnings
- Fix: Everything possible

**Integration Testing**:
- Review: just enough to execute
- 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 (e.g. in a sticky note next to the node, or a comment in the exported JSON):

```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 Structural Quirks

### IF Node Metadata

**Warning**: IF node missing `conditions.options` metadata

**Status**: False positive for IF v2.2+

**Why it occurs**: The editor adds the metadata when the node is saved - JSON written by hand or reviewed before import may lack it

**What to do**: Ignore - metadata is added when the user opens and saves the node

### Switch Branch Count

**Warning**: Switch has 3 rules but 4 output connections

**Status**: False positive when using "fallback" mode

**Why it occurs**: Fallback creates an extra output

**What to do**: Ignore if using fallback intentionally

### Credential Errors Before Execution

**Warning**: Cannot validate credentials without execution context

**Status**: False positive when reviewing static workflow JSON

**Why it occurs**: Credentials are validated at runtime, not build time - exported JSON only carries credential IDs/names

**What to do**: Ignore during review - credentials are checked when the workflow runs on the instance

---

## 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
- ✅ Community/custom nodes reported as unknown (when installed on the target instance)
- ✅ Intentional polling loops flagged as cycles (with an exit condition)
- ✅ Editor-normalized structures (IF/Switch metadata, operator structure)
- ✅ Static credential checks (validated at runtime)

**Golden Rule**: If you accept a warning, document WHY.

**Related Files**:
- **[SKILL.md](SKILL.md)** - Main guide
- **[ERROR_CATALOG.md](ERROR_CATALOG.md)** - Error types and fixes
