Repository navigation
[Bug]: Claude usage lists a <synthetic> model with no explanation #14670
Description
Activity
Note
Grok responding on behalf of Julius.
Triage
Thanks for the clear diagnosis and for laying out both options, @tris203! I confirmed this on current
main(a3abb52660).<synthetic>isn't a model. Claude Code writes it on assistant messages it makes locally, such asNo response requested.after an interrupted turn, or a local auth or rate-limit notice. Those rows have zero tokens and were never billed.parseClaudeRecordinapps/server/src/usage/usageTranscripts.tsstill keeps any assistant row with a non-emptymessage.model, so the name gets its own bucket in the Claude model breakdown. Pricing already refuses to price it (UNPRICEABLE_MODELSinusagePricing.ts), which is why the cost column says Unpriced and the token count stays at 0. The row leaves the token and cost totals unchanged. It does count toward the "unpriced records" share, though, because that share is based on how many records there are. Web and mobile both show the name exactly as stored, anddocs/user/usage.mddoesn't mention it.Recommendation
I'd go with your first option: exclude it. Session import in
AgentSessionScanner.tsalready skips this placeholder when it picks a session's model, and the usage parser should do the same by dropping<synthetic>inparseClaudeRecord, with aparseClaudeLinetest. A tooltip would put a local placeholder on both web and mobile without telling anyone anything useful about usage. One thing to keep in mind: when a real, billed response contains the textNo response requested., it's stored under the actual model name, so it should still be counted.Codex and Grok already drop zero-token usage events, so this only affects Claude.
Related
- Not a duplicate of [Bug]: Stop still kills the Claude CLI and
--resumes, so every Stop rewrites the full prompt cache (not covered by #10689) #10955 (open issue, about Stop rewriting the Claude prompt cache) or fix(server): update all Claude unified usage windows #14441 (open PR, about Claude usage windows). - fix(server): ignore malformed Claude model usage #5184 (closed PR) dealt with malformed
modelUsagetelemetry, which is a different problem. - No open PR covers this. Claude Code's own trackers describe the placeholder in anthropics/claude-code#53260 and anthropics/claude-code#57195. The part where it shows up on our Usage page is our bug to fix.
- Not a duplicate of [Bug]: Stop still kills the Claude CLI and
- addedbugSomething is broken or behaving incorrectly.Something is broken or behaving incorrectly.via-triageFiled through npx t3 triageFiled through npx t3 triage
on Oct 1, 2026 - added 2 commits that reference this issue
on Oct 4, 2026
Before submitting
Area
apps/server
Steps to reproduce
continue.Expected behavior
The model breakdown lists only real models, or anything else in it is explained.
Actual behavior
A model named
<synthetic>appears in the Claude usage, with zero tokens and no cost. Nothing in the UI or indocs/user/usage.mdsays what it is.Diagnosis
<synthetic>is not a model. Claude Code writes it asmessage.modelon assistant messages it generates locally without calling the API. In the transcripts I checked, every occurrence was the placeholder textNo response requested., written after[Request interrupted by user]and before the next prompt. These rows have all token counts at 0:{"type":"assistant","message":{"model":"<synthetic>","role":"assistant","stop_reason":"stop_sequence","usage":{"input_tokens":0,"output_tokens":0,"cache_creation_input_tokens":0,"cache_read_input_tokens":0}}}The Claude transcript parser keeps any assistant row with a non-empty model name and has no zero-token check, so these rows become a usage bucket:
https://github.com/pingdotgg/t3code/blob/53456bc012/apps/server/src/usage/usageTranscripts.ts#L122-L123
Pricing already knows about the name and treats it as unpriceable, which is why it shows no cost:
https://github.com/pingdotgg/t3code/blob/53456bc012/apps/server/src/usage/usagePricing.ts#L145-L160
AgentSessionScanner.tsalso already ignores it when picking a session's model.Decision needed
Two ways to resolve this, maintainer's call:
<synthetic>rows in the Claude transcript parser so the name never reaches the Usage page. Nothing is lost from the totals, since the rows carry zero tokens and were never billed.Impact
Cosmetic issue
Version or commit
main @ 53456bc
Environment
Linux, Claude Code 2.1.284
Workaround
None needed; the row does not affect token or cost totals.