Session-start sidecar request is issued twice concurrently and both are billed
Summary
At session start, the CLI issues the same sidecar request twice, concurrently — a few milliseconds apart, while the first is still in flight. Both requests reach the API, both are answered, and both are billed. It is not a retry and not a cache miss: it is one question answered twice.
Cheap per instance. Reporting it as a structural defect rather than a cost problem.
How it was observed
A local forward proxy that captures request and response bytes before any of its own processing runs. Because the capture is written pre-pipeline, the duplicate is visible as the client's own bytes rather than as anything the proxy introduced.
The population (measured 2026-08-14)
Across the capture corpus on that date: 118 duplicate request streaks, 62 double-billed, of which 47 form one tight class:
- model
claude-haiku-4-5, one message,max_tokens=32000 - every instance at session start (capture lines 3–5)
- inter-send interval 6–25 ms, median 14 ms
Model, position in the session, and interval are three independent axes, and they partition the population identically — which is what makes this one class rather than a sort order.
Both sends are real, completed calls. All 47 pairs carry distinct upstream request-ids, none null, and each member joins to its own usage record with a real final output-token count. The two answers land within a token or two of each other (16|16, 18|18, 19|19, 26|29).
It cannot be a retry, and that is measured rather than argued. The first send's own wall time to its first usage record is ~700–800 ms. The duplicate is issued 6–25 ms in. On 47 of 47 pairs the second request left before anything about the first could have been observed — there was nothing to retry yet.
Cost: 48,203 input-side tokens attributable to the duplicate sends across that corpus.
Relationship to #78420 — related symptom, different shape
I read #78420 before writing this, and this is not the same mechanism, so it should not be read as confirming that report:
| | #78420 | this |
|---|---|---|
| shape | one request whose prefix is assembled ~2x | two separate requests, byte-identical |
| when | mid-session, at 400–700k contexts | session start, first few requests |
| model reported | opus, 1M context | claude-haiku-4-5 |
| evidence of the extra call | inferred from cache_read ≈ 2.00x with negligible cache_creation | both calls directly observed, each with its own request-id and usage record |
| scale | up to 1.37M tokens in one request | 6–25 ms apart, small sidecar payloads |
Both are "requests the user did not ask for, billed to the user", which is why they are worth reading together. The evidence here does not speak to whether #78420's doubling is the same root cause, and I am not claiming it does.
What we did NOT check
Stated so the verified parts are believable:
- Whether this reproduces without a proxy in the path. The duplicate appears in pre-processing captures, which rules the proxy out as its source, but does not prove the proxy is irrelevant to timing.
- Which client-side code path issues the second send.
- Whether the behaviour varies by platform, CLI version, or account type — this is one machine.
- The population has not been re-measured since 2026-08-14, and cannot be from this corpus: our proxy has coalesced this class since that date, so the class is absent by construction now. The numbers above are the pre-mitigation measurement, given with their date rather than presented as current.
A note on the obvious fix
Dropping the second send is not available to a proxy — two client requests are in flight and each is owed a response. The only safe shape we found was coalescing one upstream call to both callers.
Flagging this only because "just dedupe adjacent identical requests" reads as the low-risk change and is not one: there is a separate mid-session duplicate class where the second send is a genuine retry, and suppressing it there would leave a real retry unanswered. Whatever is done client-side presumably has better information available than a proxy does.
---
🤖 Generated with Claude Code
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗