Error: File content (28375 tokens) exceeds maximum allowed tokens (25000). Please use offset and limit parameters to read specific portions of the file, or use the GrepTool to search for specific content
The file was found, opened and measured. Nothing was sent to the API — there is no status code here, no request id, and nothing was billed — so this is not an auth problem, not a rate limit, and not the model refusing anything. It is also not your context window being full: this fires on a session whose window is otherwise empty. One read was declined by a ceiling your tool enforces on its own, on its own machine, before the content could enter the conversation.
Data as of 2026-09. Vendor limits and defaults change; check the official docs for current values before acting on any number below.
Two numbers, and only one of them is about you
The number on the left is your file. It moves every time you touch the file and tells you nothing except how far over you are. The number on the right is the per-read ceiling in force for that tool on that machine, and it is the one worth reading, because it is much smaller than the context window — deliberately.
That gap is the whole design. A context window is a budget shared by the system prompt, tool definitions, memory files, every previous turn, and every file already read. A per-read ceiling stops any single file from eating a large slice of that shared budget in one move, at a point where the damage is still cheap to undo. When the budget does run out, the failure is much worse and much later: the request stops being accepted at all, with the oversized content already sitting in the history.
So the ratio matters more than the overage. If your file is slightly over, one
limit parameter clears it. If it is several times over, the ceiling is not the
obstacle — the plan is. A file that large would occupy a meaningful share of the
window for the entire rest of the session.
The part that changes your plan: reads do not stick
Here is the thing most people do not know, and it removes the appeal of “just get the whole file in once.”
A file you read is ordinary message history. When the conversation is compacted,
that history is summarized away with everything else. Claude Code re-reads up
to five of the files touched in the session afterward — the most recently
modified ones — and a file over 5,000 tokens does not come back as contents
at all. It comes back as a path reference, shown as Referenced file instead of
Read.
Read that number against the one in your error message. Any file big enough to trip this ceiling is, by a wide margin, also big enough to be dropped to a path reference at the first compaction. You cannot buy permanent residency in the context window by reading a file in full; you can only pay for it on every turn until it is summarized away. Which means the offset/limit and search advice in the message is not a consolation prize for hitting a limit. It is what the workflow should have looked like anyway.
Is retrying useful?
No. The same file tokenizes to the same count and hits the same ceiling, every time.
This is arithmetic, not luck. There is no queue, no capacity, no backoff that changes the number on the left. A retry wrapper around a file read turns one clear refusal into a stream of identical refusals, and because the failure is local and free, that loop runs fast and quietly for as long as you let it.
One case looks like a retry succeeding and is not: a file being written to while you read it — a log, a build artifact, a generated bundle — produces a different count each attempt and may occasionally squeak under. That is a race, not a fix, and it argues against reading the file whole at all. The test costs you nothing: run the identical read twice and compare the two token counts. Identical numbers mean a stable file and a deterministic refusal. Different numbers mean the file is moving under you.
Which read were you actually trying to do?
Match yourself to exactly one of these before changing anything, because they have different fixes and the error message looks the same for all four.
- You can name a string that would appear near your answer — a function name, a config key, an error message, an import. You do not want the file, you want a location in it. This is the search case.
- You need a specific region — one function, one section, one block of a long config. You know roughly where it is but not the line. Search, then read around the hit.
- You genuinely need every line — a full review of a module, a rewrite. The ceiling is telling you something true about the unit of work, not about the file.
- It is not prose or code at all — a lockfile, a minified bundle, a CSV export, a JSON dump, generated client code. Ask whether a human would read it top to bottom. If not, the tokens buy you almost nothing at a high price.
What to change in each case
- Search case — use the search tool the message names. A search returns the matching lines, not the file, so it costs a fraction of the window and leaves room to search again. This is the cheapest steady state, not a workaround.
- Specific region — search first to get a line number, then read with offset and limit around it. Two bounded operations beat one refused read, and you can stop as soon as you have what you came for.
- Every line genuinely needed — split the task rather than the read. Work through the file in bounded passes with a concrete question for each, so the window holds conclusions instead of raw text. If the whole file has to be in context simultaneously for the task to make sense, the task is too big for one session and no read parameter fixes that.
- Not meant to be read — extract instead. Query the JSON, grep the lockfile for the one package, ask for the schema rather than the dump. Reading it in full would fill the window with structure and leave you paying for it every turn afterward.
- You have a configurable ceiling and are tempted to raise it — treat that as the last move, not the first. Raising it does not create window space; it relocates the failure to a later turn, where the content is already in the history and your options are worse. Check your tool’s official docs for the current setting and default rather than assuming the number in your message is universal.
Confirming you fixed the workflow, not this one call
One successful read proves only that one read fit. The failure you are actually trying to avoid is the session that fills up three tasks from now.
Re-run the same piece of work from the beginning, then open /context, which
breaks down everything occupying the window by category. The honest pass has two
properties: the work completed, and files are not the dominant category
afterward. If the file category still dominates, you have moved the problem
rather than solved it — and the next thing you will see is a compaction, which
will quietly turn that expensive read into a path reference anyway.
For a workflow you plan to keep using, run it twice in fresh sessions and compare how much of the window is consumed by the same point in the task. A change that merely delays the wall is easy to mistake for a fix on a single run.
Related limits that look like this one
- The same ceiling thrown as MaxFileReadTokenExceededError is the form you get in a crash log or a non-interactive run, where the question is how your automation should handle it rather than what to type next.
- prompt is too long is where this ends up if you keep raising ceilings instead of reading less — the window is full and the whole request is refused, not one tool call.
- Error during compaction: Conversation too long is the trap one step further on: the window is full of file contents and compaction itself no longer has room to run.
- API Error: Claude’s response exceeded the output token maximum is the mirror image — a cap on what the model writes, unrelated to what you read.
- The context window calculator turns the number in your error message into the thing you actually care about: what share of the window that file would have held for the rest of the session.