What was actually happening before the fix
The search step only ever tried the first result that wasn't already a duplicate, fired it off to the processing workflow as a webhook call it didn't wait on, and then exited — no matter what happened next. The processing workflow, on the other end, had zero error handling around its download step. A blocked download — a license restriction, a copyright claim, anything the downloader couldn't get past — crashed the entire execution and routed to a generic error-alert workflow. Since the caller had already exited by the time that alert fired, nothing else got tried. One blocked video meant zero videos published that day, and the only sign anything had gone wrong was a generic alert that didn't say "try the next one," because nothing was listening for that instruction in the first place.
Splitting the webhook into two real outcomes
The processing workflow's webhook was set to fire-and-forget. I changed it to wait for a response, then wrapped the actual download step so a failure produces a distinct output branch instead of crashing the run — a blocked download now returns a small JSON payload saying so, on a separate path from the one that continues into the rest of the pipeline. The success path still fires its response immediately so the caller isn't blocked on the full render — it just needed the failure branch to exist so a rejection had somewhere to go besides "unhandled."
Making the caller actually listen
On the search side, the fix was to stop treating that webhook call as fire-and-forget: parse the response, check whether it reports success, and only stop there if it does. A failure routes to a skip notification and loops back into the search results to try the next candidate — instead of the workflow just being done after one attempt regardless of the outcome. A network hiccup on that call doesn't crash the loop either; it's set to continue past connection errors rather than take the whole run down over something that has nothing to do with the actual video.
Why this matters more than it looks like
None of this is complicated logic — it's a webhook that reports its real outcome and a caller that checks before giving up. The part that's easy to skip is deciding, up front, what "failure" looks like for a step that's allowed to fail sometimes (a blocked download is not the same category of problem as a broken workflow) and making sure that distinction actually reaches the node that decides whether to retry. Most of the times I've seen a daily automation quietly produce nothing, it wasn't because everything broke — it was because the one thing that failed was treated the same as the whole pipeline failing.
n8n Automation Hub