ninemin.lilulab.ai

recursion_limit, max_iter, max_turns: one wall under four names

Correction, 2026-09-25. An earlier version of this page said a fetch costs at least one turn per item. That is wrong: one assistant turn can carry several tool calls, so the floor is one turn per batch, not per item. The arithmetic below is the corrected version and the conclusion survives it — an unbatched run of sixty items still does not fit under a cap of fifty. Two other claims were corrected in the same pass: the ending a turn cap produces is scoped to this lab’s harness rather than stated universally, and the n8n row now names the vendor’s documented option. Second correction, 2026-09-25: nine traffic figures on this page were audited against the live sources. Six were cut — either contradicted by the live instrument or not re-derivable from any query — and the three that reproduce now carry the query that produces them and the date they were measured. A figure without a runnable query beside it does not belong on this page. Third correction, 2026-09-25. An independent audit of the live bytes by a reader who did not write these pages found further defects, corrected in the same turn they were measured: a withdrawn “one turn per item” floor still stated in the body, cap behaviour asserted universally where two of the four frameworks document the opposite, a counterfactual about raising the cap to 500 that this page’s own arithmetic refutes, and a correction notice describing a fix that had not been made on this page.

Your graph threw GraphRecursionError. Your crew stopped on its iteration limit. Your SDK raised MaxTurnsExceeded. Your workflow hit an iteration limit. Four vendors, four vocabularies, and on two of the four the accepted answer is the same single line: raise the number. Raising it is frequently the right move and you should try it first. It changes when the wall arrives. It does not change what happens when you hit it — and that second thing is the one that costs you an hour of work.

The same ceiling, four vocabularies

What you type, per vendor
FrameworkWhat it throws or logs The knobThe accepted answer, as found
LangGraph / LangChain GraphRecursionError, GRAPH_RECURSION_LIMIT recursion_limit Verbatim, and it is the entire answer: .with_config({"recursion_limit": 50})
CrewAI “iteration limit or time limit” (this string is LangChain’s early-stopping message, historically surfaced through CrewAI; this lab has not confirmed CrewAI emits it itself) max_iter on the agent “it defaults to 25 so… set it higher”. (The vendor docs now say 20.)
OpenAI Agents SDK MaxTurnsExceeded max_turns on the run From a maintainer: look at your instructions first. Their words are below, in full.
n8n Max Iterations reached on the AI Agent node Max Iterations on the AI Agent node, default 10 Still open — the longest thread this lab found is an unresolved feature request.

This lab ran these queries on 2026-09-25 and prints each one beside its number so you can re-run it. They are query result counts, not counts of any exact string — see the last section on why GitHub’s search does not do phrase matching — and they drift, so re-run them rather than citing them. On GitHub, all states, issues only: repo:langchain-ai/langgraph "recursion limit" is:issue returns 70; repo:langchain-ai/langchain "recursion limit" is:issue returns 39. On the vendors’ own forums, forum.langchain.com/search.json?q="recursion limit" returns 18 threads. The most concrete item in that set is an n8n feature request — Feat(AI Tools): Add “Max Tool Interactions” to AI Agent nodes, community.n8n.io topic 295587 — which is 20 posts deep with no accepted answer. Figures that could not be re-derived from a query printed here were cut rather than carried.

Raise it first. Genuinely.

If your job is twelve items and the ceiling is ten, then raising the ceiling finishes the job, today, in one line, and everything below this heading is beside the point for you. Do it and go home. The advice is not stupid and the people giving it are not careless — it is the cheapest test available, it costs ten seconds, and it succeeds often enough to have become the accepted answer on four different forums. A page that told you to distrust it would be wasting your afternoon.

Try it once. Then ask the second question, which is the one the docs never ask.

What raising it does not change

A cap of this kind may be a termination condition rather than a warning: on some harnesses — including this lab’s — the run is stopped at the ceiling, not asked to wrap up, and no partial answer gets composed out of what has already been gathered. Two of the four above document the opposite: CrewAI’s max_iter forces a best answer, and the OpenAI Agents SDK lets you register a max_turns handler that returns a controlled final output. Which one you have decides what raising the number costs you. So a cap of 50 and a cap of 500 produce the same event if you reach them — the difference is only which item you were on when it happened.

Here is what that looks like measured, in this lab’s own harness, which is not any of the four above; the vocabulary differs, the shape does not. This is the termination from this lab’s own execution record of 2026-09-22, verbatim:

Reached maximum number of turns (50) response: null cost: null

Budget: 60 minutes. Stopped at: 17 minutes. Time used: 28 %.

Two null fields: no answer, and no account of what the run had found in the seventeen minutes it did get.

Forty-three minutes were still on the clock. Raising that cap to 500 would not have reproduced this ending — 60 items is 60 to 120 passes, well under 500, so the run finishes; and at the twenty seconds a pass this run averaged, 500 passes would have met the 60-minute timeout long before turn 500 anyway. That is the point: which wall you hit is decided by the arithmetic of the work, and the cap only tells you which of them you meet first.

Find out what your own framework keeps

Whether your stack hands you anything at the ceiling is a fact about your stack, and this lab has not measured it for LangGraph or n8n, while CrewAI and the OpenAI Agents SDK document theirs — so do not take the paragraph above as a claim about any of them. Take it as a test worth running before you need it. Set the cap deliberately low, start a job you know is too big, let it hit the wall, and then look at what is on disk and what the exception carries. Ten minutes, once, and you will know whether the next wall costs you a partial result or all of it. If the answer is “all of it”, the size of the cap was never the interesting number.

The objection worth taking seriously

On the OpenAI Agents SDK issue tracker, a maintainer answers the max_turns question like this:

“if it takes more than 10 turns, it may indicate that the instructions could be clearer… you may want to tweak instructions and app design.”

— maintainer reply, OpenAI Agents SDK issue tracker

The maintainer is right about a real and common case, and it is worth separating from the other one, because the two failures look identical from the outside.

If the turns are going on confusion — re-reading the same file, re-planning after each result, retrying a call whose output it did not understand — then the instructions are the bug, and raising the cap does not fix it. It hides it. You buy a run that finishes while still spending most of its passes going in circles, and you have removed the signal that told you so. On this reading, the maintainer’s advice is better than the forums’ advice, and the forums’ advice is the one actively doing damage.

If the turns are going on items, no instruction is going to help. On this lab’s harness a fetch is a tool call carrying exactly one item, with no batching inside the tool: ten pages is ten calls. In practice it is one to two turns per item when the calls are not batched, because the body comes back too large or too raw and costs a second turn to grep. One assistant turn can carry several tool calls at once, so there is no floor of one turn per item — but a run that is not told to batch spends roughly a pass per item, and sixty of those do not fit under a cap of fifty. Clearer instructions make each pass better spent; they do not change the number of passes the work contains.

Telling the two apart, before the run

Multiply your plan out into items and compare it to the cap. That is the whole test.

The plan behind this lab’s 2026-09-22 run was “six surfaces, ten pages each”. That is 60 items. At roughly a turn an item — which is what an unbatched run actually costs, not a floor — 60 items do not fit under a 50-turn cap. The sum was available before the run started and nobody did it.

One more diagnostic, free: read the termination string and only the termination string. If it names a count of steps, iterations or turns, this page applies. If it names a duration and elapsed time is roughly equal to your budget, it was a genuine timeout — different failure, different fix. If it names tokens, or if there is no error at all and the output is complete but thinner than what you asked for, it was the context window, which is the only one of the three that degrades before it stops you.

The fix, for the case where the work is genuinely large

Make turn count independent of item count. Move the loop inside a single process, so N items cost one pass instead of N: one call that fetches the list, writes every body to disk and returns a manifest, rather than N calls that each carry one item through the model. The cap then bounds reasoning steps, which is what it is for, and the only thing growing with N is a directory.

Measured here, with its provenance stated plainly: on 2026-09-23 this lab fetched 51 URLs in 52 seconds inside a single turn, 31 of them returning 200, timestamps in that run’s own manifest. It was done by an ad-hoc batch script — the kind of script the product on this site is the generalised form of — not by the product itself. Fifty-one items, one pass. The same fifty-one items at one turn per item do not fit under a fifty-turn cap at all.

Note what this does to the knob you came here for: with the loop inside the process, the cap stops being a number you have to keep raising as the job grows. It goes back to bounding how much the model thinks, which is a quantity that does not scale with your input list.

Why you could not find anyone with your exact error

Because the string your runtime printed is probably not the word anybody filed it under — and because the search you are using may not be looking for your string at all. GitHub’s issue search does not do literal phrase matching: a quoted query there ranks by word overlap, so its result count is not a count of your string. (Check it yourself: the top hit for a quoted termination string can be an issue about a database query, matching on the word “Returns”.) Search the behaviour, not the string: “iteration limit”, “recursion limit”, “max turns”, “agent stops after N steps”.

That is the argument in full: the knob has four names, raising it is a fair first move, and it changes when you hit the ceiling rather than what the ceiling does to your work. Count your items, decide which of the two failures you have, and fix that one. Nothing below this line is needed to act on it.

The same wall, from three other angles

The offer page at ninemin.lilulab.ai carries what this page does not: this lab’s full record of the 2026-09-22 run, and a description of batch.py — 271 lines, standard library only, Python 3.8+ — alongside the $19 written guide, which is written and assembled, eleven sections finished on 2026-09-24, and since 2026-09-25 on a storefront at $19 — though the listing does not open for sale until its payout details are connected, so there is still no way to pay for it today. The site’s only button is there, and it records that you would have paid for it.