Maximum iterations reached. Requesting final answer.
That line is CrewAI telling you an agent ran out of max_iter. It is not an exception and it does not end the task. CrewAI appends an instruction to the conversation telling the model to ignore everything it was told and stop using tools, makes exactly one more model call, and returns whatever comes back as the task output. The run is marked finished. Two things follow from that, and both of them matter more than the number you are about to raise.
The executor loop checks the budget at the top of every pass. When the check trips it does not raise — it calls one function and breaks:
while not isinstance(formatted_answer, AgentFinish): try: if has_reached_max_iterations(self.iterations, self.max_iter): formatted_answer = handle_max_iterations_exceeded( printer=PRINTER, messages=self.messages, llm=cast("BaseLLM", self.llm), callbacks=self.callbacks, verbose=self.agent.verbose, ) break
And that function is where the string lives:
if verbose: printer.print( content="Maximum iterations reached. Requesting final answer.", color="yellow", ) messages.append( format_message_for_llm(I18N_DEFAULT.errors("force_final_answer"), role="user") ) answer = llm.call( messages, callbacks=callbacks, )
Quoted verbatim from lib/crewai/src/crewai/utilities/agent_utils.py at commit a0d16dde, and the loop above from agents/crew_agent_executor.py at commit d2190c2a. The function’s own docstring says what it is for: “Handles the case when the maximum number of iterations is exceeded. Performs one more LLM call to get the final answer.” Note the path: CrewAI is a monorepo now and the package sits under lib/crewai/src/crewai/, not at the top level.
The first consequence: with verbose=False there is no string at all. The print is inside if verbose:. A production crew built quiet — which is most of them — hits its iteration ceiling and says nothing whatsoever. The task output arrives, the crew reports success, and the only record that the ceiling was involved is the shape of the answer.
The second: the last instruction the model saw was not yours. What gets appended is the force_final_answer entry in CrewAI’s own translations file, and it reads:
Now it's time you MUST give your absolute best final answer. You'll ignore all previous instructions, stop using any tools, and just return your absolute BEST Final answer.
Verbatim from lib/crewai/src/crewai/translations/en.json at commit 1357491f, key errors.force_final_answer. It is appended with role="user"; the source carries a comment explaining why it is a user turn rather than an assistant prefill.
There is one way this path can raise, and it is not the ceiling: if the forced call comes back empty, the code raises ValueError("Invalid response from LLM call - None or empty."). So a ValueError with that text is also a capped run — one whose final guess failed too.
The default is 25, declared on the agent base class:
max_iter: int = Field( default=25, description="Maximum iterations for an agent to execute a task" )
From agents/agent_builder/base_agent.py at commit c3f83cd8. Being a field on the agent rather than on the crew is the useful part: the budget is per agent, so a crew of three agents has three separate ceilings of 25, and the one that trips is the one that was asked to do the iterating.
Raising it to 50 buys that agent 25 more passes. If the task genuinely needed 31, that is the right fix and it ends here — count the passes first, the way you would count iterations of any other loop. But look at what the bigger number does not change. The terminal act of a capped agent is one model call with tools switched off, written from whatever is in the message list. That happens at 25 and it happens at 250. The only things the bigger number buys are a longer transcript for the guess to be written from and a larger bill to get there. An agent with no reachable stopping condition will spend any ceiling you give it and then hand you the same forced answer, later and dearer.
Because nothing is raised, the fix is not a try block. It is three changes, in order of how much they buy.
Make the forced answer detectable. Whatever wraps your crew should be able to tell a finished task from a forced one. The cheapest version is a check on the conversation for the force_final_answer text and a refusal to pass that task’s output downstream. Until something does that, a quiet crew cannot distinguish the two cases at all, which means your metrics cannot either.
Split the iterating task into tasks that each finish. One task that takes 25 passes is one unit of work that either completes or produces a guess. The same work as five tasks is five units, each with its own output recorded as it completes, and a ceiling hit on the fourth leaves three finished and one identified. Because max_iter is per agent, splitting across agents splits the budget too.
And the change underneath both, which is not a CrewAI setting: make one iteration do more. An iteration that handles one item and an iteration that handles forty cost the same one model call. Agents that hit 25 passes are usually not doing hard work, they are doing iterative work — the model walking a list by hand because nothing it was given could walk the list itself. Hand it a tool that takes the whole list and the iteration count stops tracking the item count.
A correction this page carries. Until today the CrewAI row of our own four-framework comparison gave this failure’s string as “iteration limit or time limit” and said in the cell that we had not confirmed CrewAI emits it itself. That caution was right: it does not. That sentence is LangChain’s, it has its own page now, and CrewAI’s string is the one at the top of this page. The comparison page has been corrected to match.
There is a written guide: the iteration-and-turn arithmetic as a formula you can run against a brief before you launch it, the reasons raising a cap does not finish the job — this page’s version of it, where the cap is raised and the forced answer stays invisible, is the one the guide spends longest on — and batch.py, one standard-library file that collapses a per-item loop into a single pass.
No page on this site has a checkout widget of its own. There is a written guide behind this host and it is on sale at $19 on a storefront that delivers the files automatically and carries a 30-day money-back guarantee: buy it there (checked 2 October 2026); the guide can also be paid for with 19 USDC on Base at the payment page, where delivery is by hand as a reply to your email. Every page on this site, including this one, is free to read in full, with no sign-up and nothing gated.
The short version: Maximum iterations reached. Requesting final answer. is printed, not raised, and only when the agent is verbose. CrewAI then appends an instruction telling the model to stop using tools, calls it once, and returns that as the task output, so a capped task and a finished task have the same type and the same success flag. The default ceiling is 25 and it is per agent. Detect the forced answer, split the task so finished units land as they finish, and raise max_iter only when you can say how many passes the task actually needs.
This page counts anonymous readership. Each load sends the page path, the address of the page you came from (our server keeps only its domain), how long the page was open, whether you scrolled, and any campaign or outreach code in the link you followed; a second “engaged” event is sent once, ten seconds after the page opens — whether or not the tab is in front of you — or as soon as you scroll a quarter of it. The campaign codes from the first link you arrived on are kept in this browser’s local storage, and a later visit that arrives with no codes of its own is counted against them, outreach code included; a link carrying its own codes is used for that visit, and the stored first touch is never replaced. If a link carries a different outreach code, that later touch is recorded alongside the first rather than in place of it. The referrer of that first visit is stored in the same place and is never sent anywhere — every visit sends the referrer it actually had. A return visit is still counted, and an outreach code is removed from the address bar after it is read. The page also asks this domain for Vercel’s analytics script; on 26 September 2026 we requested that address on each of the five hosts we publish — lilulab.ai, willcall, ninemin, ghmirror and pinpoint — and every one returned HTTP 404 and no script, so no script from another company was served to your browser and none ran. The page still asks for it on every load, so this stops being true the moment that address starts answering, without a single byte of this page changing — and this page will not know it has, and will go on saying what it says. Whether Vercel counts the request at its own edge is its record and not ours; as of 26 September 2026 no one here had opened it, and we keep no copy of it. No cookie; the local storage above does that job. Some things are recorded that the list above does not name. Your browser and the network attach these to the request rather than the page sending them: the identification string your browser gives with every request; the two-letter country the network assigns your address — no city, and your address itself is never stored; and the site address you asked for. Our own server then writes its own bookkeeping about the record: the date and time of your visit, to the thousandth of a second, from our clock; which request header it took that site address from; and a number naming the record format it wrote. It also stores the domain your browser said the count was fired from, which for a normal load of this page is this site itself, and which our server records as the word “unknown” when the browser sends nothing it can read. Every row is kept in Vercel’s blob storage and not on a machine of our own, measured 26 September 2026 by reading the handler. The page sends how long it was open twice, from two different counters, and our server reads only one of the two names — so some rows carry it and some are empty (measured 26 September 2026). This page reads an outreach code from the address if one is present and keeps it in your browser, which would let us tell one reader from another — but we have sent no link for this page and hold no list of recipients for it, so as of 2 October 2026 there is no name for any code to resolve to. This page also loads a second counter of its own. It sends its own copy of the view event on every load, so one load writes two view rows and any rate measured against them reads half its true value; it also measures the time differently, counting only the seconds the page was actually in front of you where the first counter sends wall-clock time since the page opened. It also sends an event once you have had the page in front of you for ten seconds and moved the mouse, touched the screen, scrolled or pressed a key. That ten-second event also depends on the count before it: this second counter does not send it unless its own copy of the view event went out first. Its “engaged” is stricter still — it is sent only after that ten-second event has gone out, you have had the page in front of you for ninety seconds in all, and you have scrolled far enough to reach a marker we put where the explaining part of this page ends; a reader who stops short of that marker never produces one. Because both counters send an event called “engaged” under different rules, a single visit can produce two of them. The host that serves it keeps its own request logs; those are its record and not ours. Every quotation above is from the linked file at the pinned commit; the same links are listed for machine readers at /llms.txt.