[BUG] `advisor` tool doubles the reported context size, firing auto-compact at ~50% of the real window

Status Open
Reported on v2.1.220
Maintainer reply None cached
Activity 3 comments · opened Jul 27, 2026

Summary

Every turn that calls the server-side advisor tool reports an usage block
roughly 2× larger than the turn before it, because the advisor's own
forwarded-transcript prompt is summed into the same usage block as the main
turn. Claude Code treats that sum as context occupancy, so a conversation that
is really at ~85k tokens is accounted as ~175k and auto-compact fires.

Measured across 20 transcripts of one project: 27 advisor turns, 27
doublings, no unexplained doubling
, and 7 of the 16 auto-compactions in
those transcripts happen on an advisor turn
— each time with a real
conversation of only 82–100k tokens.

The generic mechanism is already acknowledged in the Anthropic cookbook
("Automatic context compaction" → Limitations and Considerations
Server-Side Sampling Loops: *"Cache tokens accumulate across sampling loops,
which can trigger compaction prematurely based on cached content rather than
actual conversation history"*). That section lists server-side web search and
server-side extended thinking as affected; advisor is not listed, and I
could not find any issue reporting it. Filing this because the advisor case is
fully deterministic and easy to measure.

Environment

  • Claude Code 2.1.220 (latest published at time of writing)
  • Linux 6.14, bash
  • Main model: claude-opus-5; "advisorModel": "opus" in ~/.claude/settings.json
  • Also reproduced on claude-opus-4-8 transcripts
  • No [1m] / extended-context model involved — plain 200k windows only

Controlled reproduction

Fresh session, no large tool results, exactly one advisor() call. Consecutive
turns from ~/.claude/projects/<project>/<session>.jsonl:

line 110  12:08:12   input 2 + cache_creation 935  + cache_read 52907  =  53,844   (Edit)
line 114  12:08:14   input 4 + cache_creation 1691 + cache_read 108008 = 109,703   (server_tool_use: advisor)
  • ratio 2.038
  • 2 × 53,844 = 107,688; observed 109,703+2,015 tokens of

advisor-specific overhead (the reviewer system prompt). Everything else is an
exact duplicate of the main prompt.

The two seconds between the turns contained a single Read whose tool_result
was a few hundred bytes. Nothing entered the conversation that could account for
+55,859 tokens.

Proof the number is not real occupancy

One transcript reports 382,597 input tokens on claude-opus-4-8 — a 200k
window, non-[1m]. A single prompt of that size cannot exist. It is
~191k main + ~191k advisor summed into one usage block.

Proof the auto-compact trigger reads this number

Every compact_boundary in the 20 transcripts whose immediately preceding turn
was an advisor turn:

| session | advisor turn (reported) | previous turn (real) | ratio |
|----------|-------------------------|----------------------|-------|
| 8cb8bc81 | 182,352 | 89,508 | 2.04 |
| 8cb8bc81 | 198,342 | 97,051 | 2.04 |
| ab157ad4 | 180,153 | 88,055 | 2.05 |
| ab157ad4 | 202,197 | 99,892 | 2.02 |
| b5af4b0d | 177,771 | 87,059 | 2.04 |
| b5af4b0d | 170,207 | 81,980 | 2.08 |
| d4d07771 | 195,019 | 96,453 | 2.02 |

A conversation of 82–100k crosses no threshold on a 200k window. The only value
that does is the sum. In the b5af4b0d / 170,207 case the compaction fired
2 seconds after the advisor turn, on a conversation whose previous turn was
81,980 and whose intervening tool_result was 294 characters.

Steps to reproduce

  1. claude with an Opus main model and "advisorModel": "opus".
  2. Work normally until the session reaches ~85k tokens.
  3. Call advisor().
  4. The context indicator jumps to ~175k and auto-compact fires immediately.

Or measure it on existing transcripts:

import json, glob
def total(u):
    return (u.get('input_tokens', 0)
            + u.get('cache_creation_input_tokens', 0)
            + u.get('cache_read_input_tokens', 0))

for f in sorted(glob.glob('*.jsonl')):          # in ~/.claude/projects/<project>/
    prev = None
    for line in open(f):
        try: d = json.loads(line)
        except ValueError: continue
        m = d.get('message') or {}
        u = m.get('usage')
        if not u:
            continue
        t = total(u)
        if t == prev:
            continue
        c = m.get('content')
        advisor = isinstance(c, list) and any(
            b.get('name') == 'advisor' or b.get('type') == 'advisor_tool_result'
            for b in c
        )
        if prev and t > prev * 1.7:
            print(f'{f[:8]}  {prev:>7} -> {t:>7}  ratio={t/prev:.2f}  advisor={advisor}')
        prev = t

Expected behaviour

The context-occupancy figure that drives auto-compact (and the status line)
should count only the tokens that are actually in the conversation, excluding
the tokens consumed by the nested server-side advisor request. The advisor's
cost is a real billing cost, but it does not persist in the context window —
the next turn's cache_read confirms this, since it returns to the
pre-advisor baseline plus the small advisor result block.

Actual behaviour

The summed usage is treated as occupancy, halving the usable window on any
session that uses the advisor, and firing auto-compact mid-task at ~50%.

Notes

  • The binary already contains a retry:advisor-strip /

tengu_advisor_strip_retry path that replays a request with advisor blocks
removed, so advisor content is already recognised elsewhere as
prompt-inflating.

  • Worst case is Opus main + Opus advisor (the only combination available when

the main model is Opus, since the advisor must be at least as capable): the
duplicate is exactly the size of the main prompt.

  • Existing workarounds, both lossy: disable the advisor (/advisor

Advisor disabled, or CLAUDE_CODE_DISABLE_ADVISOR_TOOL), or disable
auto-compact (autoCompactEnabled: false) and /compact manually. Raising
CLAUDE_CODE_AUTO_COMPACT_WINDOW is not a workaround: only advisor turns are
doubled, so a non-advisor turn would then be allowed to grow past the real
200k limit.

Possibly related

  • #50204 — same ~2× factor and same .jsonl methodology, and advisor calls

appear in the repro steps, but attributed to the display denominator on a
[1m] model. Closed as duplicate, no maintainer comment, no link to the
canonical issue.

  • #64923 — auto-compaction at ~50% reported utilisation, cause unverified.

Closed as duplicate.

  • Advisor issues covering unrelated symptoms (400s / availability): #49994,

#56515, #64158, #67609.

View original on GitHub ↗

3 Comments

bmurgic · 18 days ago

Same behavior here on 2.1.229, with one detail that narrows the cause.

The doubling is not permanent. It reverts on the next turn.

  1. Note the context usage percentage. In my run it read 5%.
  2. Call advisor().
  3. Read the percentage again. It read 9%.
  4. Send any message, or make any tool call.
  5. Read the percentage again. It read 5% again.

No content leaves the session between step 3 and step 5. The context cannot shrink on its own. So the value in step 3 is a display error, not real usage.

Auto-compact reads the same counter. In a long session it fires early, and it discards context that the session still needs. My test session sat too low for auto-compact to fire, so I confirm the meter error only.

Related: #81029 and #84738 report the same symptom. #84738 proposes that the advisor turn sums usage across its internal iterations. That cause fits the revert in step 5, because the next turn recomputes the total from the message history.

Video posted below:

https://github.com/user-attachments/assets/410083ff-39e7-4670-b369-084d18da2479

cstelmach · 17 days ago

Same bug with auto-compact off: the session stops instead of compacting

We run autoCompactEnabled: false, so we never see the spurious compaction. We get the
other end of it. 2.1.227, model: opus[1m], advisorModel: opus, macOS.

One session, consecutive records:

line 1098   input 1 + cache_creation 2,240 + cache_read   516,462 =   518,703
line 1101   input 4 + cache_creation 3,417 + cache_read 1,039,172 = 1,042,593  (advisor)
line 1111   isApiErrorMessage: true, error "invalid_request", "Prompt is too long"

Real context about 521k against a 1M window. The session stopped mid-task and needed a
manual /compact to continue.

Not a one-off. Across 5,729 local transcripts: 210 hit "Prompt is too long", 113 of
them mid-session, and 37 of those ended the session. 32 of the 37 had an advisor call
within 12 records
, against 41 of the 76 that recovered.

The ratio reproduces independently, over 53 advisor turns in 14 transcripts: 2.03x
median, p90 2.06, 51 of 53 above 1.8x, against 1.01x for 4,207 ordinary turns of which
none exceeded 1.8x. Two details fit the iteration-sum cause in #84738 rather than an inline
second copy: the growth is entirely cache_read while fresh input_tokens go 1 to 4, and
it reverts to 1.03x on the next turn.

One thing I cannot establish from outside: Whether that error is a real API rejection or a
local refusal: no isApiErrorMessage record of any kind carries a requestId (0 of 13
here, including server_error ones that certainly came from the server).

arthurmoraesfernandes-afk · 17 days ago

Your 27/27 doubling study matches — #84738 pins this mechanism with transcript-level evidence: a turn that invokes the advisor reports usage summed across usage.iterations — two full-context message iterations, so top-level usage comes out at ~2× real context (e.g. cache reads 515,122 + 515,905 → 1,031,027 reported) — and auto-compact eligibility reads the rolled-up figure. Quantified over 8 days of transcripts on one machine: every subagent auto-compaction in the window fired on the turn immediately after an inflated advisor rollup, at real contexts of 310–517K, average (preTokens − real context) ≈ 350–390K. Subagent seats consulting the advisor at checkpoints are hit hardest.