A working 3-branch report, and a 4th branch that looked identical
The workflow was simple on purpose: a Schedule Trigger fires daily, three parallel HTTP Request nodes each pull one YouTube channel's stats, and a single Code node ("Build Report") reads all three results and builds one Telegram summary plus one spreadsheet row. It had run cleanly every day for weeks. Adding a fourth tracked channel meant adding a fourth HTTP Request node — the same shape as the other three, doing the same job, reading the same API.
Bug one: "Build Report" was never actually waiting on all of them
"Build Report" had only ever been wired with a direct connection from one specific stat node — the other two were read purely through $('NodeName').first().json expressions, which only work correctly if that node has already executed by the time the expression runs. With three same-speed API calls, this was never visible: they finished close enough together that the one connected node was reliably the slowest of the three by the time it mattered. The fourth channel's HTTP call ran at a different, independent speed, and one of the original three branches (an OAuth error, returning fast with a failure rather than a slow success) now sometimes returned before the new channel's call had, tripping the whole thing over into an execution-order dependency that had been silently assumed correct for weeks.
The error was blunt: Node 'Get News Channel Stats' hasn't been executed. The fix looked equally blunt — connect every stat node directly into "Build Report," so the node's own multiple-input wiring, not an expression's silent assumption, decides when it's safe to run.
Bug two: connecting four nodes to one input doesn't mean "wait for four"
That fix shipped, and the very next manual re-run made it obvious it was wrong in a completely different way: "Build Report" ran four times in a single workflow execution — once immediately after each of its four predecessors finished, independently. Four Telegram messages landed in the same chat within seconds of each other. The tracking Sheet, which appends one row per "Build Report" run, got 16 new rows instead of 4 — each of the 4 executions itself read all 4 stat nodes' current data, so every duplicate execution wrote 4 near-identical rows.
The mental model that failed: connecting several nodes to the same input on this n8n version does not create a fan-in that waits for all of them, the way it might in a diagram on a whiteboard. Each incoming connection independently re-triggers the receiving node whenever that specific predecessor finishes. Four wires in meant four separate re-runs, not one merged run.
The actual fix: a Merge node, not more direct connections
The genuine fan-in primitive is a dedicated Merge node (mode: "append", numberInputs set to the branch count — 4 at the time, since grown to 6 as more channels were added). Each stat node was rewired into its own numbered input slot on the Merge node instead of directly into "Build Report"; the Merge node's single output then feeds "Build Report." Unlike plain multiple connections into one node, a Merge node's inputs genuinely do wait for every configured input to arrive before it emits anything downstream — this is the behavior the original wiring was mistakenly assumed to already have.
Cleaning up what the bug already wrote
By the time the fix shipped, 16 duplicate rows were already sitting in the tracker Sheet from the bad run. A disposable webhook-triggered n8n workflow (create, activate, call once, deactivate, delete — never left running) read the Sheet to identify the 16 rows by their shared timestamp, then deleted them. One more real gotcha surfaced here: the Google Sheets node's delete operation with startIndex + numberOfRows: 16 only actually deleted 1 row per call, not 16 — worked around by calling the single-row delete 16 times in a row instead (each call deletes whatever now sits at that index, since rows shift up after every delete). A fresh read afterward confirmed the Sheet was back to exactly the legitimate rows.
What actually counted as fixed
The next scheduled 08:00 CEST run was the real test: exactly one Telegram message, one row per channel written once, no duplicates. The lesson wasn't really about YouTube stats or Telegram — it's that "connect several nodes into one" and "wait for several nodes, then run once" look identical on the canvas and are not the same wiring at all. If a node has more than one direct predecessor and the number of times it should run matters, that's a Merge node's job, not a coincidence of how fast each branch happens to finish.
n8n Automation Hub