Skip to content
18px
Distributed SystemsRoutingReliabilityAI InfrastructureGo

If a Bug Hits 16% of Requests, Does It Hit 16% of Users?

How sticky routing concentrates degradation, what Anthropic’s September 2025 postmortem reveals about user impact, and a small Go lab exploring ways for sessions to escape.

October 25, 20267 min read

No. That percentage tells me how much traffic was affected. It doesn't tell me who experienced it, how often they ran into it, or whether retrying gave them a reasonable chance of escaping.

The same number of bad requests can be scattered across users or repeatedly land on the same people. Those are very different incidents to live through.

That's the part of Anthropic's September 2025 postmortem I wanted to understand better. I'm focusing on the context window routing bug and the session affinity that made its effects uneven. I built a small Go lab, sticky-routing-lab, to explore that pattern.

01What happened

On August 5, 2025, some Claude Sonnet 4 requests were sent to servers configured for the upcoming 1M token context window. Initially, about 0.8% of requests were affected.

A routine load balancing change on August 29 increased the misrouting. During the single worst hour on August 31, 16% of Sonnet 4 requests were affected.

Across the whole incident, about 30% of Claude Code users who made requests had at least one message routed to the wrong server type.

Those last figures have different denominators and different windows. The 16% describes requests in the worst hour. The 30% describes users with any exposure over the incident. I can't use them as a direct conversion between requests and users.

Anthropic's postmortem describes an infrastructure bug. It also says routing was sticky: after a request reached an incorrect server, follow-ups were likely to reach that server again.

02A routing decision can outlive the request

With independent routing, each request gets a fresh draw. A bad destination on the previous request doesn't determine the next destination.

With perfectly sticky routing, the draw happens when the session is assigned. Later requests inherit it. The randomness hasn't disappeared. It has moved from the request to the session.

That creates correlation. If I'm unlucky on assignment, trying again inside the same session may just exercise the same broken path.

Here's a deliberately small example: 4 users, 8 requests each, with each user making those requests in a single session. Both columns contain the same 8 bad requests. G means good and B means degraded.

UserOne possible random spreadConcentrated in a sticky session
AB G G G G B G GB B B B B B B B
BG B G G G G B GG G G G G G G G
CG G B G G G G BG G G G G G G G
DG G G B B G G GG G G G G G G G

The request-level total is identical. In the random example, everyone experiences some degradation. In the sticky example, user A experiences it throughout the session while everyone else sees normal behavior.

Random routing doesn't guarantee the neat spread shown here. It's a possible outcome chosen to make the difference visible.

Stickiness hasn't increased the number of distinct users affected in this example. It has concentrated the damage. That's what I mean by changing the blast radius: both its reach and its severity matter.

Anthropic described follow-ups as likely to stay on the incorrect server. Perfect pinning is my simplified model, not a claim about its exact implementation.

03Why I'd still use sticky routing

There are good reasons to preserve affinity.

A follow-up can reuse cached work. A server may already hold useful warm state for the session. Connection reuse can avoid repeated setup and help preserve locality, depending on how the service is built.

If I make every request forget its previous destination, I may throw away work that makes the system practical to operate.

So I wouldn't look at this incident and conclude that sticky routing is a bad design. I'd ask what happens when the destination is wrong.

The same affinity that preserves useful state can preserve exposure to a fault. That tradeoff belongs in the design, alongside whatever benefit motivated stickiness in the first place.

04The same bug on other platforms

The reported impact differed across serving platforms. Misrouted Sonnet 4 traffic on AWS Bedrock peaked at 0.18%. On Google Cloud's Vertex AI, the reported figure was under 0.0004%. Anthropic's own API reached 16% during its single worst hour.

These aren't measurements from a shared window, and the postmortem doesn't explain why they differed. I wouldn't infer a routing architecture from those percentages.

Anthropic also says Claude runs across AWS Trainium, NVIDIA GPUs and Google TPUs. That's serving context, not a causal explanation for this routing bug. The postmortem does not connect the hardware, including NVIDIA, to the misrouting.

05What I built

I built sticky-routing-lab in Go to isolate the routing question. It's a simplified model, not a reconstruction of Anthropic's system.

The model treats a short request reaching the long-context pool as the degraded case. That's the simulated fault being studied. It isn't a claim that long-context servers inherently handle short requests poorly.

I'm comparing these policies:

  • Random: Make a fresh routing decision for every request. This is the baseline for seeing how independent decisions distribute exposure.
  • Sticky: Keep the session's assigned destination. This shows how an initial bad assignment can turn into repeated degradation.
  • Sticky with TTL: Let the assignment expire so later requests can get a fresh decision. Expiration creates another chance to escape, but reselection can still choose the wrong pool.
  • Sticky with a guard: Refuse short requests on the long-context pool. This tests an explicit compatibility rule instead of relying entirely on the router to make a valid assignment.
  • Sticky with a quality check: Unpin a session when the quality check detects degradation. This tests whether a session can leave an unhealthy assignment after the problem becomes visible.

The guard and the quality check address different points in the path. The guard acts on a known routing mismatch. The quality check acts on an observed outcome.

Neither policy should be read as a claim about what Anthropic implemented.

For the comparison, I care about the fraction of requests degraded, the fraction of users affected at least once, and each user's degraded share. I also want to see whether bad requests arrive in runs within a session.

[RESULT: Insert measured request-level and user-level impact for each routing policy, including the run configuration and observation window.]

[CHART: per-user degraded share]

That chart should make concentration visible. A global average won't tell me whether degradation was broadly scattered or dominated particular sessions.

[CHART: users vs requests affected]

[RESULT: Insert the observed effect of TTL, the routing guard, and quality-triggered unpinning. Note any sessions that were reassigned to the wrong pool.]

The quality-check variant needs careful interpretation. Detecting a simulated bad outcome is easier than deciding whether an arbitrary generated response is degraded. The lab lets me study what happens after detection; it doesn't solve production quality evaluation.

06What I'd take into a design review

Measure affected users alongside affected requests. I'd want both denominators and the observation window written down. A worst-hour request metric and an incident-wide user metric answer different questions.

I'd also keep users and sessions separate. A user can create multiple sessions, so counting affected sessions doesn't automatically give me affected users.

Look at the distribution. I'd want the per-user degraded share and the pattern within sessions. A user who encounters an occasional failure has a different recovery path from someone whose follow-ups keep landing on the same broken destination.

The average can hide that difference even when it is calculated correctly.

Make sticky sessions easy to unstick. I want affinity to be revocable during an incident. TTL is useful, but waiting for expiry shouldn't be the only way to move a session.

I'd ask what happens after unpinning, too. If the faulty destination is still eligible, clearing the assignment may simply send the session back. Recovery needs a routing decision that can actually change its experience.

Check quality on real production traffic. I'd want a quality signal that covers the actual routing path, with appropriate controls over user data. A healthy connection doesn't establish that the response was correct.

Anthropic said it would run quality evaluations continuously on true production systems. I read that as a reason to test the deployed path, including routing and configuration, rather than assume an evaluation elsewhere covers it.

The question I'd keep beside the lab results is small: when this route goes bad, can the session leave? Then I'd check the distribution to see who stayed stuck.

You made it to the end.

1,413 words across 6 sections. If it was useful, pass it on to someone who'd enjoy it.

Bhupesh Kumar

Bhupesh Kumar

Technical lead at dizzaract, building backend systems, real-time media and infrastructure that scale.