The ten ways LLM telemetry goes wrong
Your cost dashboard, your token budget and your error rate all read the numbers that an instrumentation library writes on a span. When one of those numbers is wrong, nothing fails. The dashboard is just wrong, with full confidence. These are the classes of bug that spantruth measures, each one checked against what the provider actually sent.
To see which of them your own versions have, run uvx spantruth doctor in your
project.
spantruth 0.4.2 · 2026-11-07T20:45:58+00:00 · the full report · source
ST01Ghost span
The app made the call, and no finished span ever reaches a backend.
The call is not there. Its cost, its latency and its error are all absent, and nothing says so. Streams that the app leaves early or that fail mid-way are the usual victims.
- In this run
- 25 cells in 3 libraries
- Largest cost error
- -100%
- Example
anthropic/async-stream-dropped: never ended: chat claude-sonnet-5-5- In public
- openllmetry#4536 (reported by armanunix), openllmetry#4643 (reported by chrikrah), openinference#3790, fixed (reported by feiiiiii5), openinference#3930, fixed (reported by armanunix), openlit#1828 (reported by chrikrah)
ST02Double span
One call reports its token usage on two spans.
A backend that sums token attributes across spans counts the call twice. The Anthropic SDK traces itself since 1.14.0, so a library on top causes this unless it handles the SDK's span, as OpenInference does since openinference-instrumentation-anthropic 3.1.1.
- In this run
- 15 cells in 1 library
- Largest cost error
- +100%
- Example
anthropic/async-basic: expected 1, reported 2: usage on 2 spans: anthropic.messages.create, chat claude-sonnet-5-5- What to do today
- Let one side report the call: set ANTHROPIC_OPEN_TELEMETRY=false, or pass open_telemetry=False to the client.
- In public
- langfuse#18978: dashboards show about 2x (reported by rvndbalaji), opentelemetry-python-genai#971 (reported by lmolkova), openinference#4119, fixed (reported by PabloPardoGarcia)
ST03Cache-blind tokens
Cached tokens are left out of the input count, or their own counts are wrong.
The cost of a cached call is wrong, because a cache read costs a fraction of an input token and a cache write costs more than one. Your cache hit rate is wrong too.
- In this run
- 8 cells in 2 libraries
- Largest cost error
- -100%
- Example
anthropic/cache-hit: expected 4096, reported nothing- In public
- openllmetry#4583 (reported by armanunix)
ST04Phantom tokens
The span reports more tokens than the provider sent, or invents a count.
The cost is too high. When a stream carries no usage and the library estimates from the text, the number looks real and is not.
- In this run
- 8 cells in 3 libraries
- Largest cost error
- +0.2%
- Example
openai/stream-no-usage: expected nothing, reported 7: estimated: the stream carried no usage- In public
- openllmetry#4377 (reported by arthi-arumugam-git)
ST05Vanishing tokens
The span reports fewer tokens than the provider sent, or none.
The cost is too low, and a token budget or a rate alert fires late or never.
- In this run
- 9 cells in 1 library
- Largest cost error
- -100%
- Example
anthropic/async-stream: expected 2311, reported nothing- In public
- sentry-python#7948 (reported by chrikrah), logfire#2549 (reported by chrikrah)
ST06Hidden reasoning
The reasoning tokens that the provider reported do not appear on the span.
Reasoning is billed as output, so the total can be right while the reason for it is gone: you cannot see how much of your bill is thinking.
- In this run
- 15 cells in 5 libraries
- Example
anthropic/stream-thinking: expected 1103, reported nothing- In public
- openllmetry#4660 (reported by chrikrah), inspect_ai#5815 (reported by chrikrah)
ST07False OK
A call failed, and its span does not say so, or does not say how.
Your error rate is too low. A stream that dropped its connection counts as a success in every panel that filters on status or on `error.type`.
- In this run
- 19 cells in 3 libraries
- Example
anthropic/async-stream-dropped: expected ERROR, reported OK- In public
- openllmetry#4535 (reported by feiiiiii5), langfuse-python#2039 (reported by chrikrah)
ST08False alarm
A call succeeded, and its span says it failed.
Your error rate is too high. A 429 that the SDK retried and recovered from pages somebody for an outage that the user never saw.
- In this run
- Not seen
ST09Silent stop
The finish reason is missing or wrong.
You cannot tell a complete answer from one that hit `max_tokens` or a content filter, so truncated answers look the same as finished ones.
- In this run
- 60 cells in 4 libraries
- Example
anthropic/async-basic: expected end_turn, reported nothing- In public
- anthropic-sdk-python#2055 (reported by chrikrah)
ST10Observer effect
The instrumentation changes what the application receives.
The telemetry is not the worst part: your app behaves differently with tracing on. It gets other chunks, another exception, or it hangs.
- In this run
- Not seen
A cost figure is for the token mix of one scenario, at list price from developers.openai.com and platform.claude.com on 2026-11-06. Input tokens include cache reads and writes, so the uncached part is input minus reads minus writes. A span that never ends reports nothing, and usage on two spans counts twice only in a backend that sums across spans. A backend with another formula shows another number.