コンテンツにスキップ

Claude CodeのContext Usageが約2倍になる現象をJSONLで追跡した

Claude Code の Context Usage が突然約 2 倍になる現象を、ローカルのセッション JSONL から追跡しました。今回のログでは、advisor前後の 2 回分の使用量を合算した値が、表示値と一致しました。ログで確認できた原因と、/compact後に再発した理由を説明します。

Claude Code で長時間の作業を続けていると、Context Usage が直前の約 2 倍へ突然増えることがありました。その後のターンでは元に戻る場合がある一方、増加後の値がコンテキスト上限へ達すると、作業を継続できなくなることもあります。

今回確認したセッションでは、Context Usage が 100%へ到達したため、途中で手動の/compactを実行しました。しかし、compact 後にも同じ約 2 倍の増加が再び発生しました。

Claude Code は、会話履歴や読み込んだファイル、コマンド出力、各種指示などをコンテキストウィンドウへ保持します。公式ドキュメントのExplore the context windowによると、/contextで使用状況を確認でき、/compactを実行すると会話履歴を要約してコンテキストを圧縮できます。

そこで、Claude Code がローカルへ保存しているセッション JSONL を調べました。その結果、今回のセッションではadvisorを挟んだターンで、前後 2 回のmessage iteration が top-level usage へ加算されていました。2026 年 9 月 12 日時点では、Anthropic の公式 Claude Code リポジトリにも同じ計上問題を扱う Issue が複数あります。

検証条件

この記事で使用する一次情報は、実際の Claude Code セッションから取得した JSONL です。

項目 内容
検証日 2026-09-12
メインモデル claude-opus-5
調査対象 Claude CodeのセッションJSONL
発生した症状 Context Usageが一時的に約2倍になる
復旧操作 Context Usageが100%に達した時点で/compactを実行

Claude Code CLI の正確なバージョンは、今回保存したログ抜粋から確認できません。そのため、手元で発生した現象について特定バージョンへ原因を限定しません。

公式ドキュメントのManage sessionsによると、Claude Code はセッションを~/.claude/projects/<project>/<session-id>.jsonlへ保存します。各行にはメッセージ、ツール呼び出し、usage などのメタデータが JSON として 1 件ずつ入っています。

Context Usageが約2倍になったターン

Context Usage が増加したターンを JSONL から抽出すると、次の 4 件が確認できました。同じmessage.idを持つレコードが複数存在したため、表では重複を除いています。

この表で比較するのは、ターン全体で報告された使用量(top-level usage)と、同じターン内で最後にモデルを実行したときの使用量(最後のmessage iteration)です。数値の単位は tokens で、比率は前者を後者で割った値です。

Message top-level usage 最後のmessage 比率
...JMr 458,101 229,885 1.993倍
...Zkm 773,711 387,986 1.994倍
...C4Y 977,128 489,622 1.996倍
...JPh 310,927 157,108 1.979倍

最も大きかったターンでは、top-level usage が 977,128 tokens まで増えていました。このターンのusage.iterationsは次のとおりです。

{
  "id": "msg_011CexMoLK5Cv53ZUHWM8C4Y",
  "model": "claude-opus-5",
  "top": 977128,
  "iterations": [
    {
      "type": "message",
      "tokens": 487506
    },
    {
      "type": "advisor_message",
      "tokens": 489153
    },
    {
      "type": "message",
      "tokens": 489622
    }
  ]
}

advisor_messageの 489,153 tokens が top-level usage へ加算されたようにも見えますが、実際にはそうなっていません。977,128 という値は、advisor前後の 2 つのmessageを足した値と 1 token の差もなく一致します。

487,506 + 489,622 = 977,128

同じ関係は残りの 3 件でも成立しました。

1
2
3
4
228,216 + 229,885 = 458,101
385,725 + 387,986 = 773,711
487,506 + 489,622 = 977,128
153,819 + 157,108 = 310,927

4 件すべてで、top-level usage は前後のmessage iteration を足した値でした。単に「たまたま約 2 倍になった」のではなく、同じ計算規則で値が作られていました。

advisor前後のmessageが合算されていた

今回のログでは、advisorを使用したターンが次の順序になっています。

1
2
3
4
5
message
  ↓
advisor_message
  ↓
message

977,128 tokens と報告されたターンでは、最初のmessageが 487,506 tokens、最後のmessageが 489,622 tokens でした。どちらも同じターン内で、メインのモデルが別々に実行されたときの使用量(executor iteration)です。それぞれの入力には、その時点までに蓄積した大部分のコンテキストが含まれています。

top-level usage では、この 2 つが加算されていました。この記事では、この合算を usage rollup と呼びます。

1
2
3
4
最初の message    487,506
最後の message  + 489,622
-------------------------
top-level         977,128

そのため、top-level usage をそのまま「現在のコンテキスト占有量」と読むと実態と合いません。今回のログで現在の executor context を推定するなら、最後のtype: "message" iteration を見る方が妥当です。

ただし、489,622 を厳密な意味で「真のコンテキストサイズ」と断定するわけではありません。Claude Code のコンテキストには会話履歴以外の指示や設定も含まれます。ここで確認できるのは、少なくとも 977,128 が単一の executor iteration の入力サイズではなく、2 つのmessage iteration を足した値だという点です。

Anthropic の公式 GitHub リポジトリにも、同じ構造を報告した Issue が次のとおりあります。

Issue 報告内容
#53065: advisor() tool inflates reported input tokens 約 513K tokens の executor context に対し、top-level usage が約 1.028M tokens
#81620: advisor tool doubles the reported context size advisorを挟んだターンで usage が約 2 倍になる
#84738: Advisor turns roll up usage summed across iterations advisorを挟んだターンで usage が約 2 倍になる

/compact自体は機能していた

Context Usage が 100%へ到達したため、このセッションでは手動で/compactを実行しました。compact 前後の値を比べると、最後のmessage iteration は 489,622 から 157,108 へ減っています。

状態 top-level usage 最後のmessage
compact前 977,128 489,622
compact後 310,927 157,108

この結果から、少なくとも今回のセッションでは/compact自体が失敗していたわけではありません。会話履歴の圧縮によって、executor context は約 49 万 tokens から約 16 万 tokens へ減っています。

一方、compact 後の top-level usage は 310,927 でした。この値も次の計算と一致します。

153,819 + 157,108 = 310,927

つまり、/compactによってコンテキストは縮小したものの、その後にadvisorを含むターンが発生すると、前後 2 つのmessageが再び合算されます。

1
2
3
4
5
6
7
8
9
compact前
  最後の message: 489,622
  reported:        977,128

      ↓ /compact

compact後
  最後の message: 157,108
  reported:        310,927

今回の問題は「compact してもコンテキストが減らない」ことではなく、compact 後にも同じ usage rollup が発生することでした。

約2倍の値が上限判定へ影響する

表示値だけが約 2 倍になるのであれば、問題は不正確なメーター表示に限られます。しかし、公式 Issue の報告によると、この top-level usage は auto-compaction や context limit 周辺の判定にも影響します。

Issue #81620 には、実際の会話が 82K〜100K tokens 程度でもadvisorターンで約 170K〜202K と計上され、その直後に compact が発生した例があります。Issue #84738 の報告者も、複数 iteration を合算した値によって auto-compact が本来より早く発生すると述べています。

今回のセッションでも、最後のmessageが 489,622 tokens だったターンで top-level usage は 977,128 tokens でした。1M context を前提にすれば、executor context の近似値は約 49%であるのに対し、reported usage は約 98%です。

最後の message   489,622  ≒ 49%
top-level        977,128  ≒ 98%

実際にこのセッションでは Context Usage が 100%へ到達したため、手動で/compactを実行しました。過去に同じ症状が発生した際には、約 2 倍になった値が上限を超えると Claude Code が作業を継続できなくなりました。

ただし、今回取得した JSONL だけから、停止判定に使われた内部閾値や判定順序までは確定できません。この部分については、公式 Issue で報告されている挙動と手元で観測した症状が一致している、と捉えるのが適切です。

Anthropic のCookbook: Automatic context compactionにも、一般的な注意事項として関連する記述があります。server-side sampling loop では cache tokens が複数の sampling loop をまたいで蓄積し、実際の conversation history より早く compaction が発生する可能性があるというものです。この資料は Claude Code のadvisor問題を直接説明していませんが、複数 iteration を持つ処理と compaction の組み合わせに既知の注意点があることを示しています。

別系統の約2倍問題と区別する

Claude Code には、advisorとは別に、プロンプト自体が約 2 倍になる現象を扱うIssue #78420: Prompt intermittently sent doubledもあります。報告者によると、Claude Code が会話 prefix 全体を二重に組み立て、あるターンだけ約 2 倍になった後、次のリクエストでは通常サイズへ戻ります。

症状だけを見ると、どちらも「突然 2 倍になり、その後戻る」ため区別しにくい問題です。ただし、今回のログでは次の 3 点を確認できました。

iterations:
  message
  advisor_message
  message

top-level:
  最初の message + 最後の message

ratio:
  約2.0

そのため、今回のセッションについては prompt duplication よりも、advisorを含む usage rollup で説明する方がログと一致します。

自分のセッションを確認する

同じ現象が発生しているか確認するには、Claude Code のセッション JSONL にあるmessage.usage.iterationsを調べます。対象ファイルは通常、次の場所にあります。

~/.claude/projects/<project>/<session-id>.jsonl

advisorを含むターンだけを見るには、次のjqコマンドを使用できます。

jq -r '
  select(.type == "assistant")
  | .message.usage as $u
  | select(
      any(($u.iterations // [])[]; .type == "advisor_message")
    )
  | {
      id: .message.id,
      model: .message.model,
      top: (
        ($u.input_tokens // 0)
        + ($u.cache_creation_input_tokens // 0)
        + ($u.cache_read_input_tokens // 0)
      ),
      iterations: [
        ($u.iterations // [])[]
        | {
            type,
            tokens: (
              (.input_tokens // 0)
              + (.cache_creation_input_tokens // 0)
              + (.cache_read_input_tokens // 0)
            )
          }
      ]
    }
' ~/.claude/projects/<project>/<session-id>.jsonl

今回のセッションでは同じmessage.idが複数回記録されていました。このコマンドの出力も同じターンを重複して含むため、-rを-cに替えて 1 行形式で出力し、sort -uで重複を除くと確認しやすくなります。

約 2 倍になったターンだけを抽出する場合は、次のコマンドを使用できます。

jq -r '
  select(.type == "assistant")
  | select(.message.usage != null)
  | .message.usage as $u
  | (
      ($u.input_tokens // 0)
      + ($u.cache_creation_input_tokens // 0)
      + ($u.cache_read_input_tokens // 0)
    ) as $top
  | [
      ($u.iterations // [])[]
      | select(.type == "message" or .type == "fallback_message")
      | (
          (.input_tokens // 0)
          + (.cache_creation_input_tokens // 0)
          + (.cache_read_input_tokens // 0)
        )
    ] as $messages
  | ($messages[-1] // $top) as $last
  | select(
      ($messages | length) >= 2
      and
      ($top / (if $last == 0 then 1 else $last end)) >= 1.7
    )
  | [
      .message.id,
      .message.model,
      ("top=" + ($top | tostring)),
      ("last_message=" + ($last | tostring)),
      ("ratio=" + (
        ($top / (if $last == 0 then 1 else $last end))
        | tostring
      )),
      ("iterations=" + ($messages | tojson)),
      ("types=" + (
        [($u.iterations // [])[] | .type]
        | tojson
      ))
    ]
  | @tsv
' ~/.claude/projects/<project>/<session-id>.jsonl | sort -u

今回のログでは、次のような結果になりました。

1
2
3
4
msg_...JMr  claude-opus-5  top=458101  last_message=229885  ratio=1.9927...
msg_...Zkm  claude-opus-5  top=773711  last_message=387986  ratio=1.9941...
msg_...C4Y  claude-opus-5  top=977128  last_message=489622  ratio=1.9956...
msg_...JPh  claude-opus-5  top=310927  last_message=157108  ratio=1.9790...

typesが["message","advisor_message","message"]となり、topが前後 2 つのmessageの合計と一致していれば、今回と同じ usage rollup が起きている可能性が高いと判断できます。

当面の回避策

手元で実際に確認できた復旧方法は/compactです。今回のセッションでは、最後のmessage iteration が 489,622 から 157,108 へ減り、作業を継続できる状態へ戻りました。

ただし、/compactは usage rollup そのものを解消しません。その後にadvisorを含むターンが発生すると、top-level usage は再び約 2 倍になりました。

Issue #81620 では、advisorを無効にする方法や、auto-compact を無効にして手動で/compactする方法が回避策として挙がっています。ただし、これらは Issue 投稿者による回避策であり、この記事の環境ではadvisorを無効化した長時間セッションまでは検証していません。

また、CLAUDE_CODE_AUTO_COMPACT_WINDOWなどで閾値だけを引き上げる方法には注意が必要です。公式ドキュメントのEnvironment variablesによると、この環境変数は auto-compaction の計算に使う context capacity を変更する設定であり、モデル自体の context window を拡張するものではありません。

今回の原因に対して閾値だけを変更すると、通常ターンで本来の context limit へ近づきすぎる可能性があります。そのため、少なくとも原因を切り分ける段階では、閾値変更よりもusage.iterationsを確認する方が安全です。

まとめ

今回のセッションで Context Usage が約 2 倍になったのは、会話履歴が倍増したからではありませんでした。advisorを含むターンで前後 2 つのmessageが top-level usage へ合算される usage rollup が原因です。/compactで executor context は約 16 万 tokens まで減りましたが、その後のadvisorターンで再び約 2 倍に計上されたため、compact の失敗とは区別できます。

長時間セッションで Context Usage が突然約 2 倍になった場合は、表示値だけから会話履歴の倍増と判断せず、次の順で切り分けます。

  1. セッション JSONL のusage.iterationsに、advisor_messageを挟んだ 2 つのmessageがあるか確認する
  2. top-level usage が前後 2 つのmessageの合計と一致すれば今回と同じ usage rollup の可能性が高いので、コンテキストの占有量は最後のmessageで見積もる
  3. advisor_messageがなく、あるターンだけ約 2 倍になる場合は、Issue #78420 の prompt duplication のような別系統の問題を疑う
  4. 上限に達したら/compactで作業を継続する(今回のセッションではこれで復旧できた)が、rollup は残るため、auto-compact の閾値だけを引き上げる前に原因を切り分ける

公式 Issue の報告どおり、この値が auto-compaction の判定にも使われているなら、表示だけの問題として放置できません。2026 年 9 月 12 日時点では、Claude Code の公式 GitHub リポジトリで同じ問題を扱う Issue #53065、#81620、#84738 が Open です。

参考資料