name: n8n-workflow-debug-vps
description: Debug n8n workflows on VPS via PostgreSQL — workflow versioning architecture, SQL node updates, task-runner error diagnosis
category: devops
n8n Workflow Debug on VPS via PostgreSQL
Debug n8n workflows when the UI/API approach fails. Uses direct PostgreSQL access to inspect workflow definitions, nodes, and execution state.
n8n Version
n8n v2.9.4 on VPS (docker container named n8n, postgres container named n8n-postgres)
Architecture: workflow_entity vs workflow_history (CRITICAL)
n8n v2.x stores workflow versions in TWO places:
- -
workflow_entity— UI-visible metadata,nodescolumn (for editor),activeVersionId - -
workflow_history— execution-relevant versions,nodescolumn (what actually runs) - - A NEW entry is created in
workflow_historywith a newversionId - -
workflow_entity.versionIdis updated to the new version - -
workflow_entity.activeVersionIdis NOT changed automatically - - The UI shows the new version but EXECUTION still uses the version pointed to by
activeVersionId - - JavaScript syntax issue OR task-runner loading an older cached version
- - Fix: update the active version in
workflow_history(see above), thendocker restart n8n - - Internal n8n task-runner error — the separate task-runner process failed to execute the node
- - Causes: version mismatch, corrupted nodes JSON, task-runner state corruption
- - Fix:
docker restart n8n(clears task-runner state) - - Use
apikeyheader (notAuthorization: Beareralone) for anonymous access - - Upsert:
POST /rest/v1/{table}?on_conflict=Idwith headerPrefer: resolution=merge-duplicates - - HTTP 201 = success, HTTP 400 = bad request (check
codeandmessagefields) - - Column names are case-sensitive in REST queries (
Idnotid) - - Supabase native node has known UI issues with Match Column dropdown and field mapping
- - HTTP Request with raw REST API calls is more predictable and debuggable
- - IP: 31.97.243.106
- - SSH:
sshpass -p 'Marcia19671951@' ssh -o StrictHostKeyChecking=no root@31.97.243.106 - - n8n postgres:
docker exec -i n8n-postgres psql -U n8n -d n8n - - n8n container restart:
docker restart n8n
The activation bug
When you PATCH /rest/workflows/{id} via REST API:
Publishing via UI also creates a new version and updates activeVersionId. But programmatic PATCH does NOT.
Symptom: "I published/updated but the workflow still fails with the same error." The workflow UI shows the new version but execution uses the old one.
Finding and fixing the active version
`bash
Check active version
docker exec n8n-postgres psql -U n8n -d n8n -c "SELECT \"activeVersionId\", \"versionId\" FROM workflow_entity WHERE id = '
`
If activeVersionId ≠ versionId, the active version is an OLD version that needs updating.
Solution: Update workflow_history directly via SQL
`python
Dollar-quoting is essential for JSON with newlines/control chars
sql = "UPDATE workflow_history SET nodes = $json$
`
Complete workflow update script (Python on VPS)
`python
import subprocess, json
1. Get workflow from n8n REST API
r = subprocess.run(['curl', '-s', f'https://n8n.example.com/rest/workflows/{wf_id}',
'-b', '/tmp/n8n_cookies.txt'], capture_output=True, text=True)
nodes = json.loads(r.stdout)['data']['nodes']
2. Upload nodes JSON to VPS (avoids newline issues in SQL)
with open('/tmp/workflow_nodes.json', 'w') as f:
json.dump(nodes, f)
r2 = subprocess.run(['sshpass', '-p', 'VPS_PASSWORD',
'scp', '-o', 'StrictHostKeyChecking=no',
'/tmp/workflow_nodes.json', f'root@VPS_IP:/tmp/workflow_nodes.json'],
capture_output=True, text=True)
3. Python script on VPS using dollar-quoting
vps_script = """
import json, subprocess
with open('/tmp/workflow_nodes.json') as f:
nodes = json.load(f)
nodes_json = json.dumps(nodes)
active_vid = '
sql = 'UPDATE workflow_history SET nodes = $json$' + nodes_json + '$json$ WHERE "versionId" = \\'' + active_vid + '\\';'
result = subprocess.run(
['docker', 'exec', '-i', 'n8n-postgres', 'psql', '-U', 'n8n', '-d', 'n8n', '-c', sql],
capture_output=True, text=True
)
print("RC:", result.returncode, "OUT:", result.stdout.strip())
"""
`
Quick Status Checks
`bash
List active workflows
docker exec n8n-postgres psql -U n8n -d n8n -c "SELECT id, name, active FROM workflow_entity WHERE active = true;"
Get workflow nodes (pretty-printed)
docker exec n8n-postgres psql -U n8n -d n8n -c "SELECT jsonb_pretty(nodes) FROM workflow_entity WHERE id = 'WORKFLOW_ID';"
Find workflows by name
docker exec n8n-postgres psql -U n8n -d n8n -c "SELECT id, name, active FROM workflow_entity WHERE name LIKE '%PATTERN%';"
`
Diagnosing execution errors
Get recent executions
`sql
SELECT id, "workflowId", status, finished, "startedAt", "stoppedAt"
FROM execution_entity
WHERE "workflowId" = '
ORDER BY "startedAt" DESC LIMIT 5;
`
Get execution error details
`bash
execution_data.data is an array of JSON objects (indices 0-4)
Index 4 contains the error object
docker exec n8n-postgres psql -U n8n -d n8n -c "SELECT LEFT(data::text, 3000) FROM execution_data WHERE \"executionId\" =
`
Common error patterns
"SyntaxError: Unexpected token '('" in Code node:
"Cannot read properties of undefined (reading 'node')":
n8n REST API Authentication
Login and save cookies
`bash
curl -s -c /tmp/n8n_cookies.txt \
-X POST https://n8n.example.com/rest/login \
-H 'Content-Type: application/json' \
-d '{"emailOrLdapLoginId": "admin@example.com", "password": "PASSWORD"}'
`
Update workflow via REST
`bash
curl -s -b /tmp/n8n_cookies.txt \
https://n8n.example.com/rest/workflows/{id} \
-X PATCH -H 'Content-Type: application/json' \
-d '{"nodes": [...], "active": true, "settings": {}}'
`
Warning: PATCH creates a new version but does NOT update activeVersionId. Use SQL update on workflow_history to activate the new version.
Supabase REST API Notes
n8n Code Node vs HTTP Request Node
For Supabase/database operations, prefer HTTP Request node over the native Supabase node:
VPS Access
Known Workflow IDs (Rocha Sales)
| ID | Name | Active |
| ---- | ------ | -------- |
| fuVLvmFke1C7GskY | RS - Automação CRM Rocha Sales | true |
| xy4Ih7ByXlow9Fw5 | RS - Sync CRM → Kanban Map (Etapa) | true |
| JI3Ke5qDgZQWxz9d | RS - Sync CRM Browser (Webhook) | true |
| 56ea2d1a-2a62-476b-92c1-59712166a44a | (legacy) | true |