Build1 publisher3 min readPublished
A webhook burst of 20-plus n8n executions was misread as the model getting worse
Lars Winstand traced 429s, doubled tool calls and inconsistent output in an n8n agent flow to a burst of simultaneous executions, and fixed it by capping production concurrency at 20 in the orchestrator.
The Engineer · Build desk

What happened
- A webhook burst landed around 20-plus executions on one of Lars Winstand's n8n flows almost simultaneously.
- The flow then returned 429s on OpenAI-compatible requests, fired a couple of tool calls twice, retried one branch enough to make the run look random, and produced output inconsistent enough to read as the model degrading.
- Winstand tightened the prompt, changed model settings, considered swapping endpoints and reviewed retry behaviour, and reports that none of it fixed the underlying problem.
- Setting N8N_CONCURRENCY_PRODUCTION_LIMIT=20 did more for reliability than prompt edits, model swaps or retry tweaks, according to his account.
- With the cap in place n8n stops running every production execution immediately and queues the excess, so LLM requests reach providers in a more controlled pattern.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- decision It reorders the debugging queue for anyone running trigger-driven agent flows: shape the traffic and re-measure before spending a day on prompt variants or a model swap.
- constraint Prompt changes leave the number of concurrent requests exactly where it was, so the whole class of semantic fixes is unavailable for this failure mode.
- exposure A retry policy tuned for isolated failures becomes an amplifier once failures correlate, and the provider limit you hit is the thing that correlates them.
- cost The account reports fewer fake model-quality investigations after the change, which is engineering time that was being spent on the wrong subsystem.
Concurrency collision and semantic failure look identical if you only read outputs. Winstand says the clue was timing: failures clustered around bursts, clean runs happened when traffic was spaced out, and the same workflow looked stable when only a few executions were in flight [6][7]. You can run that check without touching the prompt: sort your failures by arrival time, and if the bad ones cluster, the model is not the variable.
A webhook burst fans out into concurrent executions, each one calls the LLM, some calls come back 429, and the retry logic fires [2][3][9]. Retries land on top of a burst that has not drained yet [4]. Winstand's warning is specific: 20 executions retrying aggressively at the same time turn a brief provider limit into a self-inflicted traffic storm [10]. Duplicate tool calls then make outputs look inconsistent, and the inconsistency is what gets reported as model quality [4].
The failure list he gives spans three separate components, all set off by the same burst. The provider returns the 429 [2]. The doubled tool calls trace back to the workflow's own tool idempotency, or lack of it [2][8]. And the randomness came from one branch retrying enough times to make the whole run look random [2].
`N8N_CONCURRENCY_PRODUCTION_LIMIT=20` is the line that changed the behaviour [5]. What it does is narrow: n8n stops letting every production execution run immediately, and extra executions queue instead [11]. The burst still arrives, and the provider sees it spread out instead of all at once. Winstand set it as a Docker Compose environment variable, and notes the same variable applies on Render, Railway, Fly.io or Kubernetes runtime config [12][13].
Before that, he tried tightening the prompt, changing model settings, considering an endpoint swap, and looking at retry behaviour, and reports none of it fixed the core issue [14]. Read that sequence as evidence: three of those four moves change what the model reads or which model reads it, and the number of requests open at once stays exactly where it was.
The number itself does not transfer; the ordering does, which is cap concurrency, then measure, then argue about the prompt. Twenty is what one deployment needed against one provider's rate limits, with that workflow's tool calls and that downstream API. Winstand's own framing is that under burst you are testing provider rate limits, queue behavior, retry policy, tool idempotency and downstream API stability at the same time [8]. Change any of those and the right cap moves.
Winstand wrote that a lot of what people call model instability is really queueing chaos with better branding [15].
One caveat on the reported result. What he reports after the change is fewer 429 failures, fewer duplicate tool calls and more runs completing on the first attempt [16]. There are no before-and-after counts in the post, no error-rate percentages, and no traffic volumes. So this is a single practitioner's account of one deployment, and its value sits in what it explains about the failure, more than in the number it landed on.
Retries deserve their own review item after this. A retry policy tuned for isolated failures is a multiplier under correlated failures, because the correlation is what produced the 429 in the first place [10]. Capping concurrency at the orchestrator bounds the multiplier without touching the retry config at all.
What to watch
- Whether n8n documents a recommended default for N8N_CONCURRENCY_PRODUCTION_LIMIT and stops leaving production executions unbounded.
- Before-and-after error rates from a deployment with real traffic volumes, which the post does not provide.
- Whether retry policies in agent orchestrators gain burst-aware backoff, so a correlated 429 does not multiply.