n8n logon8n Automation Hub
Build breakdown

The Google Sheets "Update" Bug That Published the Same Video Twice

Build breakdown · n8n workflow · August 27, 2026

Two identical YouTube uploads of the same short appeared eight hours apart, and nothing in the workflow's execution log looked like a failure — every node had returned green. The bug wasn't in the upload step at all. It was in the step that was supposed to mark the job done.

Workflow at a glance
  1. A publisher workflow picks one "ready" row from a queue sheet, uploads it, then updates that row's status to "published"
  2. The Google Sheets "update" node matched rows using matchingColumns: ["video_id"]
  3. video_id values repeat across different parent videos in the same sheet (every video reuses generic ids like 01_hook, 02_test2)
  4. The status update silently landed on the wrong row sharing that id — the row that was actually published never flipped to "published" and got picked again on the next run
  5. Fixed by matching on row_number instead, the one column guaranteed unique across the whole sheet
Screenshot of the actual n8n workflow canvas: the football-clip publisher whose Update Queue Row node matched on the non-unique video_id column

The actual workflow canvas, straight from my n8n instance.

A queue sheet with a status column

The publisher workflow reads a Google Sheet where each row is one short clip: a video_id, a status (ready / published), and metadata for the upload. A scheduled trigger picks the first row still marked "ready," publishes it to YouTube, and writes the resulting status and video URL back to that row. Straightforward, and it had been running three times a day for weeks without incident.

Why matching on video_id looked fine

The Update node's `matchingColumns` was set to `video_id` — find the row with this id, write these new values into it. That's a completely normal pattern for a Sheets update, and it worked correctly for a long time, because most of the time the id being matched genuinely was unique enough not to collide. The problem was structural, not occasional: every parent video in this pipeline generates a handful of short clips with the same small set of generic ids — `01_hook`, `02_test2`, and so on — reused fresh for every new video. `video_id` was only unique *within* one video's clips, never across the whole sheet.

What actually happened on the day it broke

A run published one row correctly, then went to write `published` back to it — and matched a different, older row that happened to share the same `video_id` from a completely different video. That older row got overwritten with the new run's status and URL. The row that had actually just been published stayed marked `ready`. The next scheduled run picked it up again, saw a "ready" row, and published it a second time — a genuine duplicate upload, not a retry of a failed one. Collateral damage went further: the wrongly-overwritten row's own real published URL, from days earlier, was gone too, replaced by data that had nothing to do with it.

The fix

`matchingColumns` changed from `video_id` to `row_number` — a value that's unique by construction, one row, one number, no reuse possible — and the field being written was changed from a hardcoded `0` to the actual row number of the item currently running. The update now can only ever land on the row that triggered it.

The lesson generalizes past this one workflow

Any Sheets-based queue where "update the row I just processed" uses an id field for matching is only as safe as that id's uniqueness *across the entire sheet*, not just within the group it was generated for. An id that looks unique because it's descriptive — `01_hook`, `intro_clip`, `step_3` — is exactly the shape that repeats once there's more than one parent item in the same sheet. The safe match key is whatever the sheet actually guarantees is one-of-a-kind: a row number, a UUID, a timestamp — never a label.

Got a Sheets-based queue workflow you're not fully sure is safe?

I review n8n Google Sheets integrations for exactly this class of silent-wrong-row bug — no error thrown, just quietly incorrect data.