Skip to content

MaxFileReadTokenExceededError: File content (31252 tokens) exceeds maximum allowed tokens (25000). Use offset and limit parameters to read specific portions of the file, or search for specific content instead of reading the whole file

You are looking at an exception class, not a terminal message, and that is the most informative thing about it. Something in your stack threw rather than returning a result — so you found this in a log file, a JSON payload, a crash report or a CI transcript rather than on screen. Nothing reached the model provider: no status code, no request_id, no billing. It is not a file permission error either — the file was opened and tokenized successfully, which is how anyone knows the size. And it is not the context window being full; this ceiling applies to one read, and it fires on an empty session.

Data as of 2026-09. Vendor limits and defaults change; check the official docs for current values before acting on any number below.

Answer one question before you fix anything: did the run continue?

An exception in a log tells you the read failed. It does not tell you whether the work failed, and those need different responses.

Read what comes immediately after it in the same log. If the next entries show another tool call — a narrower read, a search, a different file — the agent was told the read failed and adapted. Your job is then a cost and reliability problem, not an outage: the run worked, it just wasted a step, and it will waste that step every time until you change how files get read.

If nothing follows, the turn ended there. Now you have an automation that stops on a file of a certain size, which means it stops unpredictably, because the size depends on whichever repository it happens to be pointed at that day. This distinction is invisible from the exception itself and decides whether you are tuning a workflow or fixing a break.

Catch the class, never the sentence

The message is built from the file in front of it. The token count is per-file, the ceiling depends on the tool and its configuration, and the prose — which parameters it names, whether it says “search for specific content” or names a specific search tool — is product copy that gets reworded between releases.

The class name is the part with a contract. If you are writing a handler, match on the error’s name or type. A handler that string-matches exceeds maximum allowed tokens is a handler that will silently stop matching after some future release, and the failure mode of that is not an exception you can see — it is your fallback branch quietly never running again. The same reasoning applies to the wording on any sibling page here: treat the class as the identifier and the message as display text.

There is a human-readable twin of this exact condition, without the class name, which is what an interactive session prints: Error: File content exceeds maximum allowed tokens covers the same ceiling from the “what do I type next” side, including why the ceiling sits so far below the context window and what the token budget actually costs you per turn.

Is retrying useful?

No, and this is the specific error where a retry loop is most likely to go unnoticed.

The read is deterministic: the same file produces the same token count and the same refusal on every attempt. Nothing upstream is involved, so there is no capacity to wait for and no backoff that helps.

What makes it dangerous in automated code is that the failure is cheap. Nothing is sent to the API, so a retry costs no tokens and almost no time. A generic retry wrapper — the kind applied broadly to “tool errors” — will spin on this at full speed, produce no cost signal, and keep going until your job hits its wall clock. If you have a catch block around tool calls, check now whether this class reaches it, and make sure the branch that handles it changes the call rather than repeating it.

The one variation worth knowing: a file being actively written produces a different count each attempt and can occasionally slip under the ceiling. Compare the counts in two consecutive failures. Identical numbers mean a static file and a deterministic refusal. Different numbers mean you are reading a moving target, which is its own bug.

Make the read fit before it is attempted

Every fix below is about not reaching the ceiling, because there is no post-failure recovery that is better than not failing.

  • Your agent reads files it chose itself — give it a search tool and say in the instructions that searching is the default and whole-file reads are the exception. The ceiling exists because a large read is expensive even when it succeeds; the model has no way to know a file’s size before asking for it.
  • Your code picks the files — check the size before you read. You do not need a token count to make the decision; a byte-size threshold well under the ceiling filters out the pathological cases (generated bundles, data exports, lockfiles) without a tokenizer.
  • You need the whole file and it is genuinely needed — read it in bounded chunks with offset and limit, and cap the number of chunks. An uncapped chunk loop over a very large file does not fail; it succeeds all the way into a full context window, which is a far more expensive failure one turn later.
  • You are in a long-running session — remember that these reads do not persist. After a compaction, only a handful of recently modified files are re-read, and any file over 5,000 tokens returns as a path reference rather than contents. Code that assumes “I read it earlier, so it is in context” is wrong for exactly the files large enough to produce this exception.
  • You own the tool that throws — return a structured error the model can act on, including the size it saw and the parameters it could use. That is why the message names remedies at all: an error the model can act on is one retry inside the turn, not a dead run.

Confirming the handler works, not just that today’s file fits

The weak confirmation is running the job again and seeing it pass. Today’s repository has today’s files in it, and the whole point of this error is that it appears when the input changes.

Confirm two things separately. First, trigger the condition on purpose — point the workflow at a file you know is far over the ceiling — and check that your handler runs, that the log shows the narrower call it fell back to, and that the run finishes. A fallback branch that has never executed is a branch you have no evidence about. Second, run the real workload end to end twice and assert the class name does not appear in the logs at all. One clean run proves that no oversized file happened to be in scope; two runs over different inputs start to mean something.

If you are handling this inside an agent loop, add a counter: the number of times the fallback fires per run is the metric that tells you whether the workflow improved or merely learned to recover.

  • MCPContentTooLargeError is the same ceiling applied to an MCP server’s response instead of a local file read — worth reading if the oversized content came back from a tool you did not write, because half the fix lives on the server.
  • prompt is too long is what a chunked read loop without a cap eventually produces, and it is the error to compare against when deciding how aggressive your chunk limit should be.
  • Error during compaction: Conversation too long is the state a long automated session reaches when file content crowds out the room compaction needs to run.
  • The context window calculator is the quickest way to decide what a safe chunk size and chunk cap are for the model your job is running against.