Hello Again n8n Community,
I’m encountering a different persistent issue with an n8n workflow on version 1.91.3 (self-hosted, Docker on Linode) and would greatly appreciate any insights or known workarounds.
My Goal: I have an API endpoint (Webhook trigger) that checks if a text segment exists in a PostgreSQL database.
If the segment exists, it should respond with {"status": "ok"}
. (This part works).
If the segment does NOT exist (Postgres SELECT finds 0 rows), it should insert the segment and respond with {"status": "created"}
. The problem is that this “not found” path consistently returns an empty string ""
to the HTTP client instead of the desired JSON response.
Core Problem: When my Postgres SELECT
node outputs 0 items (segment not found), subsequent nodes intended to create a default item (e.g., containing a found: false
flag) for a downstream IF
node are failing to produce any output items themselves. This happens even when these “normalizer” nodes are configured with settings that should guarantee an output.
Troubleshooting Steps & Observed Behaviors:
Postgres SELECT
Node:
This node correctly executes its query.
When no segment is found, it correctly outputs 0 items.- Attempt 1: Using a “Code” Node as a Normalizer:
Configuration: Placed afterPostgres SELECT
; Mode: “Run Once for All Items”.
JavaScript was designed to return[{ json: { found: false, ... } }]
if($input.all()).length === 0
.
Symptom: WhenPostgres SELECT
outputted 0 items, this Code node also produced 0 output items (n8n UI showed “Execute this node to view data”).
Debugging:console.log()
statements at the script’s start did not appear in n8n Docker logs, suggesting the script didn’t execute. - Attempt 2: Using a “Set” Node as a Normalizer (Named “CheckIfSegmentFound”):
Configuration: Placed afterPostgres SELECT
; Settings Tab: “Always Output Data” = ON; Parameters Tab: “Keep Only Set” = ON.
Test 2a (Dynamic expression): Valuefound
= expression{{ $items("Postgres_Node_Name").length > 0 }}
.
Symptom: Produced 0 output items (Execution #100).
Test 2b (Static value): Valuefound
= static booleanfalse
.
Symptom: Still produced 0 output items (Execution #102).
Test 2c (Isolated Set node execution - input disconnected, static value):
Result: This WORKED. The Set node correctly produced one output item. This suggests “Always Output Data” can function in isolation but fails when triggered by a 0-item input stream from a connected node. - Attempt 3: “Merge before Normalize” Strategy (from AI suggestions):
- Structure:
Webhook
&Postgres (SELECT)
→MergeInputStreams
node (Mode: Append) →NormalizeAndCombineData
(Code node) →IF
node.
TheNormalizeAndCombineData
(Code node) was set to “Run Once for All Items”. Its JavaScript used$items("NodeName")
to get data fromWebhook
,Code1
(my original hash calc node), andPostgres
(SELECT node). The intended JavaScript is below.
Symptom (Execution #105): ThePostgres (SELECT)
node itself errored with “Referenced node is unexecuted. An expression references the node ‘Code1’, but it hasn’t been executed yet…” This occurred even though the n8n UI execution path showed “Code1” immediately preceding it and highlighted as green (successfully executed). This specific error prevented full testing of the Merge strategy.
JavaScript for NormalizeAndCombineData
(Attempt 3):
`JavaScript// — Configuration: Node names used —
const POSTGRES_SELECT_NODE_NAME = “Postgres”; // Actual name of Postgres SELECT node
const WEBHOOK_NODE_NAME = “Webhook”; // Actual name of Webhook node
const HASH_CALC_NODE_NAME = “Code1”; // Actual name of hash calculation node (e.g., “Code1”)
// — End Configuration —
let outputJson = {
found: false,
segment_id: null,
language_code: null,
content: null,
hash: null,
debug_messages:
};
try {
outputJson.debug_messages.push(“NormalizeAndCombineData script started.”);
console.log(“NormalizeAndCombineData: Script execution started.”);
const pgSelectItems = $items(POSTGRES_SELECT_NODE_NAME);
const webhookItems = $items(WEBHOOK_NODE_NAME);
const hashCalcItems = $items(HASH_CALC_NODE_NAME);
outputJson.debug_messages.push(pgSelectItems count: ${pgSelectItems.length}
);
outputJson.debug_messages.push(webhookItems count: ${webhookItems.length}
);
outputJson.debug_messages.push(hashCalcItems count: ${hashCalcItems.length}
);
if (pgSelectItems.length > 0 && pgSelectItems[0].json && pgSelectItems[0].json.segment_id !== undefined) {
outputJson.found = true;
outputJson.segment_id = pgSelectItems[0].json.segment_id;
outputJson.debug_messages.push(Segment FOUND in DB. ID: ${outputJson.segment_id}
);
} else {
outputJson.found = false;
outputJson.debug_messages.push(“Segment NOT FOUND in DB by Postgres SELECT.”);
}
if (webhookItems.length > 0 && webhookItems[0].json &&
webhookItems[0].json.body && webhookItems[0].json.body.body) {
const webhookBodyData = webhookItems[0].json.body.body;
outputJson.language_code = webhookBodyData.language_code;
outputJson.content = webhookBodyData.content;
outputJson.debug_messages.push(Webhook data retrieved: lang='${outputJson.language_code}', content='${outputJson.content ? outputJson.content.substring(0, 30) + "..." : "null"}'
);
if (outputJson.language_code === undefined) outputJson.debug_messages.push(“Warning: ‘language_code’ is undefined from Webhook.”);
if (outputJson.content === undefined) outputJson.debug_messages.push(“Warning: ‘content’ is undefined from Webhook.”);
} else {
outputJson.debug_messages.push(“ERROR: Webhook data structure error.”);
console.error(“NormalizeAndCombineData: Webhook data error. webhookItems:”, JSON.stringify(webhookItems));
}
if (hashCalcItems.length > 0 && hashCalcItems[0].json && hashCalcItems[0].json.hash !== undefined) {
outputJson.hash = hashCalcItems[0].json.hash;
outputJson.debug_messages.push(Hash retrieved: ${outputJson.hash}
);
} else {
outputJson.debug_messages.push(“ERROR: Hash data not found from '” + HASH_CALC_NODE_NAME + “'.”);
console.error(“NormalizeAndCombineData: Hash data error. hashCalcItems:”, JSON.stringify(hashCalcItems));
}
} catch (error) {
outputJson.debug_messages.push(EXCEPTION: ${error.message}. Stack: ${error.stack}
);
console.error("NormalizeAndCombineData: EXCEPTION - ", error);
outputJson.found = outputJson.found || false;
}
outputJson.debug_messages.push(“NormalizeAndCombineData script finished.”);
console.log(“NormalizeAndCombineData: Script finished. Returning:”, JSON.stringify(outputJson));
return [{ json: outputJson }];`
Summary of Unexplained Behaviors in n8n v1.91.3:
- Code Node (“Run Once for All Items”): Appears not to execute its script when direct input is 0 items.
- Set Node (“Always Output Data: ON”): Fails to output (even static values) when direct input from a connected node is 0 items (though works in isolated test with no input).
- Node Data Referencing: A node (
Postgres SELECT
) reported its successfully executed direct predecessor (Code1
) as “unexecuted” (Execution #105).
Questions for the Community / Support:
- Are these known bugs or limitations in n8n v1.91.3?
- Could environmental factors (Docker, Node.js,
N8N_RUNNERS_ENABLED
) cause this? - Besides upgrading, are there other robust workarounds for v1.91.3 to ensure an IF node reliably gets an item if a database query returns 0 rows?
- Why would a node report its successfully executed predecessor as “unexecuted”?
Any insights for n8n v1.91.3 would be greatly appreciated. This is a critical blocker. Thank you.