Huny's Dev Blog
huny.dev

Claude Messages API Message Threads: Separate 5-Minute Server State, Prompt Caching, and 404 Replays

Learn how Claude Messages API Message Threads (message-threads-2026-08-12) cut multi-turn TTFT, why prompt caching is still required for token savings, and how to handle 5-minute expiry replays.

Hun Jang
Hun Jang Nov 4, 2026

A conceptual illustration showing only the new turn delta traveling from the client's full conversation history into an ephemeral 5-minute server memory ring and four prompt-cache slots before inference. This is not an actual console screenshot.

On November 2, 2026, Anthropic launched Message Threads (message-threads-2026-08-12 beta) for the Messages API, allowing long-running conversations and agent loops to send only new messages on subsequent turns rather than re-uploading the entire conversation history every time. You initialize a thread with thread: {"type": "create"} on the first request, and follow up with thread: {"type": "continue", "previous_message_id": "..."} carrying only the new turn.

The core engineering takeaway: Message Threads optimize request transport and preprocessing latency (TTFT), but they do not replace Prompt Caching (cache_control) or client-side conversation storage. Because the model still reads the reconstructed conversation on every turn, your input token bill remains identical unless you also configure prompt caching. Moreover, server-side threads are best-effort ephemeral state that expire after 5 minutes of inactivity and are deleted within 1 hour of last use—meaning your application remains the source of truth and must be ready to replay the full conversation in a new create request whenever a continue call returns 404 thread_not_found.

This guide analyzes the request field contracts, the 4-breakpoint caching limit, and replay recovery patterns based on the Claude Platform Release Notes, the official Message Threads documentation, and the Prompt Caching guide. It does not report live production TTFT measurements; the local Python checks below verify request validation and replay sanitization logic.

1. Separate Message Threads, Prompt Caching, and Managed Agents Sessions

Although all three features deal with multi-turn context on the Claude platform, they target different layers of the stack and carry distinct billing and lifecycle rules.

Dimension
Message Threads (message-threads-2026-08-12)
Prompt Caching (cache_control)
Managed Agents Session Threads
Primary Bottleneck Solved
Eliminates repeated payload uploads, JSON validation, and re-tokenization of prior turns (lowers and stabilizes TTFT)
Reuses KV cache prefixes across turns to cut model compute time and input token cost (0.1x base input rate; 0.025x on Fable 5.1 & Mythos 5.1)
Manages full agent execution state including cloud sandboxes, tool loops, and mounted memory stores
Effect on Token Billing
No token discount. You upload fewer bytes, but standard input/output token rates still apply to the full reconstructed conversation
Direct cost reduction. 5-minute TTL write is 1.25x, 1-hour TTL write is 2x, and cache reads drop to 10% (or 2.5–5% on select models) of base input price
Bills per underlying model request and sandbox usage, with optional hard session spend caps
Lifecycle & Storage
Ephemeral server memory only. Expires 5 minutes after the last request and is deleted within 1 hour (no list, read, or delete endpoints)
5-minute default (or 1-hour) TTL measured from request start and refreshed on cache hits
Durable server-side session resource inspectable via GET /v1/sessions/... and event streams
Source of Truth
Your client application. The API does not confirm on create or continue whether a turn was stored; you discover expiry on the next continue
The request payload itself; a cache miss still succeeds because the full prompt is present
Anthropic's Managed Agents service persists the session event log

In short, for 500K–1M token agent loops, enable Message Threads to shrink network transfer and validation overhead, and pair them with a top-level cache_control: {"type": "ephemeral"} (or explicit block breakpoints) so each turn also reads prior history from the prompt cache.

2. Create-Only, Fixed, and Free Fields: Avoiding thread_fingerprint_mismatch

When building raw HTTP requests or calling client.beta.messages.create directly without the SDK thread helper, most 400 errors stem from violating the field contract between create and continue requests.

Field Group
Parameters
On create Requests (Turn 1 / Replay)
On continue Requests (Later Turns)
Failure Mode & Operational Rule
Create-only
system, tools
Send full definitions along with any block-level cache_control breakpoints
Must be omitted completely. Sending either field—even set to null—is rejected
Returns 400 invalid_request_error immediately if system or tools appears in a continue payload
Fixed
model, tool_choice, thinking, mcp_servers (except auth token), context_management, output_config, skills in container, top-level cache_control, anthropic-beta set, presence of fallbacks
Send initial configuration values
Must be sent on every turn with identical values. The API does not persist MCP server URLs or container IDs across turns
Any divergence returns 400 thread_fingerprint_mismatch naming the mismatched fields. Start a new create thread to change a fixed field
Free
max_tokens, stop_sequences, stream, metadata, service_tier
Send desired values
May change freely from turn to turn
If max_tokens truncates a response mid-tool-call, the API serves the reply but does not store the turn, causing a 404 on the next continue

Two subtle interactions require careful handling in production code:

  1. The 4-breakpoint cache_control ceiling across turns and replays: Any request using thread may carry at most 4 cache_control breakpoints. The top-level cache_control counts as 1, and breakpoints placed on system and tools during the create request continue to count on every subsequent continue request. Breakpoints on earlier stored message blocks do not count during continue calls—but if the thread expires and you replay the full conversation in a new create request without stripping those older message breakpoints, exceeding 4 total breakpoints triggers 400 thread_unsupported_request (unsupported: ["cache_control"]).
  1. Preserved thinking blocks when changing system or tools: On Claude Opus 5.5, Sonnet 5.5, Haiku 5.5, Fable 5.1, and Mythos 5.1, starting a new create request with modified system or tools invalidates earlier thinking and redacted_thinking blocks in the history and can return a 400 error. Strip all earlier thinking blocks from the replayed history whenever you change system or tools.

3. Recovery Matrix for Expiry, Refusals, and Fallback Models

Because a thread is append-only and each response ID can be continued at most once, production agents need deterministic recovery logic for five common outcomes.

Condition / Error Code
Root Cause
Required Client Recovery Action
404 thread_not_found
5-minute idle TTL expired, 1-hour max lifetime reached, prior turn ended in a truncated tool call, different API key/workspace/IAM principal used, or first image added to a text-only thread
Strip cache_control breakpoints from earlier message blocks in your local history copy and send the full conversation with system and tools in a new thread: {"type": "create"} request. If the very next continue still returns 404, fall back to unthreaded requests
400 thread_already_continued / thread_continue_in_flight
A retry reused a previous_message_id that was already continued, or the prior request is still generating after a dropped stream
Wait for the in-flight turn or replay the full conversation in a new create request. When streaming, never send a continue request after message_start—wait until message_stop arrives
stop_reason: "refusal"
Safety classifiers declined the turn. The server may still hold the refused turn in the thread, and a continue call cannot remove it
Never continue from a refused response ID. Drop or rephrase the offending turn in your local copy and start a new create request from the history prior to the refusal
fallback_message in usage.iterations
Server-side fallback (server-side-fallback-2026-07-01) routed the turn to a fallback model. Because a thread binds to a single model, fallback turns are never stored
Do not wait for a 404 on the next turn. Immediately send the full conversation (including the fallback response) in a new create request, either retrying the primary model or pinning the new thread to the fallback model
400 thread_unsupported_request
Request combines thread with Message Batches, Token Counting, on-demand Compaction (compact-2026-09-04), >4 cache breakpoints, HIPAA-enabled orgs, or Inference Hooks
Inspect error.details.unsupported (e.g., cache_control, context_management, hipaa, inference_hooks) and either remove the conflicting feature or send the request without thread

4. Validating Thread Requests and Sanitizing Replays in Python

If you use the official SDK helper (client.beta.messages.thread(...)), it automatically omits system and tools on continue turns, replays once on thread_not_found, and strips earlier message breakpoints on replay. When orchestrating raw payloads across custom proxies or multi-provider routers, the dependency-free Python validator below enforces these invariants before a request hits the network.

Scope Verified Locally

Executing this validation and replay-sanitization logic in a local Python environment verified four boundary scenarios:

  1. Valid continue turn at the 4-breakpoint boundary: Combining a top-level cache_control (1), initial system breakpoint (1), initial tools breakpoint (1), and one new message block breakpoint (1) while raising the free max_tokens field from 1024 to 2048 passed with zero errors.
  1. Create-only field leak detection: Including "system": None on a continue payload was flagged as 400_create_only_present:system.
  1. Fixed-field drift detection: Switching model from claude-opus-5-5 to claude-sonnet-5-5 mid-thread was caught as 400_thread_fingerprint_mismatch:model.
  1. Replay breakpoint sanitization: Replaying a 3-turn history where every user turn carried a block breakpoint initially totaled 6 breakpoints (exceeding the limit of 4), and strip_earlier_message_breakpoints() reduced the replay payload to exactly 4 breakpoints.

5. Production Rollout Checklist (Plus November 30 Deprecations)

  • Combine thread with top-level cache_control: Pass cache_control: {"type": "ephemeral"} on every request in the thread so you get both smaller network uploads and cached input token pricing.
  • Configure an unthreaded fallback path: If the first continue right after a replay still returns 404 thread_not_found, drop the thread parameter and continue statelessly (or set unsupported_request_behavior="continue_unthreaded" in the SDK helper).
  • Keep Token Counting and Compaction separate: Never pass thread to /v1/messages/count_tokens or alongside on-demand compaction (compact-2026-09-04). When compacting history, start a fresh create thread seeded with the summary message.
  • Prepare for the November 30, 2026 removals: Per the October 30 and September 30 release notes, both fast mode (speed: "fast") on claude-opus-4-8 and the claude-sonnet-4-5-20250929 model will be removed on November 30, 2026 and will return hard errors rather than falling back. Migrate long-running agent loops to claude-opus-5-5 or claude-sonnet-5-5 ahead of the deadline.

References

Last verified: November 4, 2026

Korean version: Claude Messages API Message Threads 해부: 5분 서버 스레드·프롬프트 캐싱·404 리플레이 분리해 설계하기Claude Messages API Message Threads 해부: 5분 서버 스레드·프롬프트 캐싱·404 리플레이 분리해 설계하기

추천 글