[BUG] Resumed session drops a tool from the parent's initial tools array (EndConversation), so its first request misses the prompt cache

Status Open
Reported on v2.1.270
Maintainer reply None cached
Activity 0 comments · opened Sep 14, 2026

What happens

A resumed session (--resume <session-uuid>, which forks) does not reproduce the parent's tools array when the parent had a server-gated tool, here EndConversation, in its tools array from its first request. The fork's first request goes out without that tool and receives it a few seconds later as a deferred_tools_delta attachment. The prefix therefore differs early, and the fork's first request misses the prompt cache for the whole conversation, although the cache is well within its TTL.

Tools and system prompt that arrived after the parent's first request are restored correctly on resume. Only a tool present in the parent's initial tools array is lost.

Environment

  • Claude Code 2.1.270, Windows 11, background sessions (claude --bg)
  • --safe-mode --tools "Bash,PowerShell,Read,Grep,Glob", so no ToolSearch and the tool cannot be deferred
  • --model claude-opus-5, --max-turns 40, --dangerously-skip-permissions
  • All cache writes are 1h (ephemeral_1h_input_tokens), so expiry is ruled out

Steps

  1. Start a background session with a restricted --tools list that omits ToolSearch, at a moment when the EndConversation tool is enabled for the process (it is gated server-side, so this happens in some sessions and not others).
  2. Let it finish a turn.
  3. About 2 minutes later, resume it: claude --bg --resume <uuid> ... with the same flags.
  4. Compare usage on the parent's last request and the fork's first request.

Evidence (one parent and fork pair)

| request | cache_read_input_tokens | cache_creation_input_tokens |
|---|---|---|
| parent, first request (tool in the array) | 8,926 | 7,776 |
| parent, last request | 27,957 | 1,118 |
| fork, first request, 2m11s later | 7,462 | 20,562 |
| a cold session without the tool, first request | 7,462 | 7,701 |

  • The fork's first read (7,462) equals the static prefix of a session without the tool, so the fork's tools array lacked it.
  • 3 s into the fork its transcript has an attachment of type deferred_tools_delta with addedNames: ["EndConversation"].
  • A second parent and fork pair, where the parent never had the tool in its array, resumed 26 s later with a full hit (read 31,790, creation 698). The same machine, flags, worktree handling and version, so forking itself does not break the cache.
  • --disallowedTools EndConversation does not keep the tool out of the request, so there is no workaround from flags.

Expected

On resume, the fork's first request should carry the same tools array as the parent's last request, as recorded in the parent's prompt_snapshot, so the prefix matches and the cache is read.

Impact

About 20K tokens written instead of read on the first request of each affected resume. In our automation this is roughly 1 in 5 resumes for sessions started with a restricted tool list. No noticeable latency cost.

One test resume on 2.1.271, with the tool enabled in the parent, got a full hit. That is a single sample, so it may be fixed or it may be the race.

View original on GitHub ↗