2026년 3월 초부터 약 한 달간 Claude Code에 Prompt Cache가 제대로 작동하지 않는 버그가 있었습니다. Claude Code 토큰 비용과 프롬프트 캐싱에서 정리했듯이 Prompt Caching은 입력 토큰 비용을 90%까지 절약하는 핵심 수단인데, 이 캐시가 작동하지 않으면 비용이 크게 증가합니다. 이 글에서는 해당 기간에 발생한 캐시 버그의 원인과 영향을 정리합니다.
1. 버그 요약
2. 원인: Resume 시 메시지 구조 불일치
2.1. 근본 원인
v2.1.69에서 도입된 deferred_tools_delta 기능이 원인입니다.
이 기능은 deferred tools 목록, MCP 서버 설정, skills 정보를 메시지에 첨부하는 방식을 변경했는데, 새 세션과 재개 세션에서 `messages[0]`의 구조가 달라지는 문제가 생겼습니다.
| 세션 유형 | messages[0] 내용 | 크기 |
|---|---|---|
새 세션 |
deferred tools 목록, MCP 설정, skills, 날짜 컨텍스트 |
~13.4KB |
재개 세션 |
날짜 컨텍스트만 포함 (나머지는 messages 끝에 추가) |
~352B |
Prompt Cache는 prefix의 해시값으로 캐시를 조회합니다. `messages[0]`의 내용이 13.4KB에서 352B로 바뀌면 해시값이 완전히 달라지므로, 이전 세션에서 쌓은 캐시를 전혀 재사용할 수 없었습니다.
2.2. MCP 서버, deferred tools와의 관계
이 버그는 MCP 서버나 deferred tools를 사용하는 환경에서 더 큰 영향을 받았습니다. 다만 이것은 MCP 서버의 tool schema가 불안정해서가 아니라, deferred tools/MCP 설정/skills 정보가 resume 시 `messages[0]`이 아닌 다른 위치에 배치되어 prefix가 달라지기 때문입니다. MCP 서버가 매번 완전히 동일한 schema를 반환하더라도, resume만 하면 메시지 구조가 달라져서 캐시 미스가 발생했습니다.
v2.1.90의 수정 내용도 이를 뒷받침합니다.
Fixed
--resumecausing a full prompt-cache miss on the first request for users with deferred tools, MCP servers, or custom agents
2.3. 부수적 문제: 매 턴 tool schema 재직렬화
근본 원인과 별개로, Claude Code가 매 턴마다 MCP tool schema를 `JSON.stringify`로 재계산하여 캐시 키를 만드는 비효율도 있었습니다. 이것은 캐시 미스를 유발하는 직접적인 원인은 아니었지만 성능 오버헤드를 발생시켰고, v2.1.90에서 tool schema를 한 번만 계산하고 재사용하도록 개선되었습니다.
3. 영향 범위
이 버그는 --resume (CLI 플래그)과 /resume (슬래시 커맨드) 모두에 해당합니다.
두 방식 모두 세션 재개 시 동일한 메시지 구조 불일치가 발생하기 때문입니다.
단, Prompt Cache의 TTL이 5분이므로 실질적인 비용 손해가 발생하는 경우는 제한적입니다.
| 시나리오 | 영향 |
|---|---|
일반 연속 세션 (resume 없이) |
영향 없음. `messages[0]`이 세션 내내 안정적으로 유지 |
5분 이내에 resume |
캐시가 살아있어야 하는데 prefix 불일치로 캐시 미스 발생 → 비용 손해 |
5분 이후에 resume |
어차피 TTL 만료로 캐시 소멸 → 버그와 무관하게 비용 동일 |
|
매 호출이 새 프로세스이므로 캐시를 전혀 재활용하지 못함 → 가장 큰 피해 |
4. 비용 영향
정상 상태에서는 캐시가 쌓이면서 턴이 진행될수록 메시지당 비용이 감소합니다.
정상 (v2.1.68): 메시지 1 → $0.15, 메시지 4 → $0.02 (캐시 적중률 증가) 버그 (v2.1.69+): 모든 메시지 → $0.35~0.40 (매번 전체 히스토리를 Cache Write)
--print --resume 워크플로우에서는 cache_read 토큰이 ~11,000(시스템 프롬프트 분량)에 머물고, cache_creation 토큰이 300,000 이상으로 치솟는 현상이 관찰되었습니다.
메시지당 약 20배의 비용 증가가 보고되었습니다.
5. 수정 내용 (v2.1.90)
v2.1.90 (2026-04-01)에서 다음과 같이 수정되었습니다.
-
메시지 구조 정규화: 세션 재개 시 `messages[0]`에 deferred tools, MCP 설정, skills를 새 세션과 동일한 위치에 삽입하도록 변경
-
tool schema 재직렬화 제거: MCP tool schema를 한 번만 계산하고 캐시하여, 매 턴 `JSON.stringify`를 호출하지 않도록 성능 개선
현재 버전 확인:
claude --version
v2.1.90 이상이면 수정된 상태입니다.
6. 영향 받았는지 확인하는 방법
2026년 3월 5일~4월 1일 사이에 Claude Code를 사용했다면, 다음 방법으로 영향 여부를 확인할 수 있습니다.
6.1. Resume 사용 여부 확인
이 버그는 resume 시에만 발생하므로, 해당 기간에 resume을 사용했는지가 핵심입니다.
6.1.1. /resume (슬래시 커맨드) 확인
대화형 세션 안에서 `/resume`을 입력한 기록은 `~/.claude/history.jsonl`에 남습니다.
~/.claude/history.jsonl에서 2026년 3월 5일~4월 1일 사이의 /resume 기록을 찾아줘.
각 resume 시점에 대해, 같은 프로젝트의 ~/.claude/projects/ 아래 JSONL 세션 로그에서
직전 세션의 마지막 timestamp와의 시간 간격을 계산해줘.
5분 이내에 resume한 경우가 있는지 확인하고 싶어.
6.1.2. --resume (CLI 플래그) 확인
`claude --resume`처럼 CLI 인자로 실행한 경우는 `history.jsonl`에 기록되지 않습니다. 이 경우는 shell history에서 확인합니다.
grep "claude.*--resume" ~/.bash_history
grep "claude.*--resume" ~/.zsh_history
bash는 기본적으로 명령 실행 시각을 기록하지 않으므로 [1], --resume 사용 여부만 확인할 수 있고 5분 간격 분석은 어렵습니다.
zsh는 EXTENDED_HISTORY 옵션이 켜져 있으면 `~/.zsh_history`에 타임스탬프가 함께 기록됩니다.
--resume`을 주로 자동화 스크립트(--print --resume`)에서 사용했다면 해당 스크립트의 실행 로그를 확인하는 것이 더 정확합니다.
5분 이내에 resume한 기록이 없다면, Prompt Cache의 TTL(5분)이 만료된 후 재개한 것이므로 이 버그로 인한 추가 비용은 발생하지 않은 것입니다.
6.2. API 사용량 확인
Anthropic Console에서 해당 기간의 토큰 사용량을 확인합니다. 평소 대비 `cache_creation_input_tokens`가 비정상적으로 높고 `cache_read_input_tokens`가 낮다면 이 버그의 영향을 받았을 가능성이 있습니다.
6.3. 캐시 메트릭 모니터링
세션 중 API 응답의 캐시 관련 토큰을 확인합니다.
-
cache_creation_input_tokens: 대화가 진행될수록 감소해야 정상 -
cache_read_input_tokens: 대화가 진행될수록 증가해야 정상
버그 발생 시에는 `cache_read_input_tokens`가 낮은 값에 머물고, `cache_creation_input_tokens`가 계속 높게 유지됩니다.
Twitter
Facebook
Reddit
LinkedIn
Email