Skip to content

[BUG] _get_cache_prices bills cache reads at the full uncached rate when LiteLLM omits cache price fields #3032

Description

@abhay-codes07

Description

CostTracker._get_cache_prices (headroom/proxy/cost.py) prices provider-reported cache-read (and cache-write) tokens at the full uncached input rate whenever LiteLLM lacks explicit per-token cache price fields for the model:

uncached = info.get("input_cost_per_token")
if not uncached:
    return None
cache_read = info.get("cache_read_input_token_cost", uncached)
cache_write = info.get("cache_creation_input_token_cost", uncached)
return (cache_read, cache_write, uncached)

LiteLLM carries those two fields for only a minority of its priced models. Measured against the bundled LiteLLM pricing DB, 1681 of the models that have an input_cost_per_token lack both cache_read_input_token_cost and cache_creation_input_token_cost (Bedrock, Mistral, Fireworks, several OpenAI-compatible gateways, and so on). For every one of those models, any provider-reported cache_read token is billed at the full uncached rate inside _get_cache_prices, even though cache reads are always a discounted rate (about 10 percent for Anthropic/Bedrock, about 50 percent for OpenAI), and cache writes are billed at the plain uncached rate even where the provider charges a write premium (about 125 percent for Anthropic/Bedrock).

Impact

_get_cache_prices feeds CostTracker.totals(), which drives the /stats dollar figures. The primary accounting path, estimate_cost -> litellm.cost_per_token, prices those same cache-read tokens natively; for a field-less model it charges 0 for the cache-read slice. So for the 1681 long-tail models the two paths disagree in opposite directions on every cache-warm request: totals() over-charges cache reads at the full rate while the budget path under-charges them at 0. The dashboard cache breakdown then does not reconcile with the primary cost accounting for the same traffic.

Concrete example (bundled LiteLLM DB): mistral/mistral-large-latest, input 5e-07/token, no cache fields. 10k cache-read tokens: litellm.cost_per_token returns 0.0; _get_cache_prices returns the full 0.005.

Suggested fix

When the LiteLLM cache field is absent, fall back to the provider cache economics the dashboard already uses (_CACHE_ECONOMICS in the same module): price cache reads at the provider read_multiplier and cache writes at the write_multiplier fraction of the uncached rate, defaulting to Anthropic's multipliers when the provider is unknown (matching the existing default in build_prefix_cache_stats). That is both closer to reality than the full uncached rate and closer to the primary litellm.cost_per_token path than the status quo.

Reported by @EvolveAegis in #2620 (comment) as a distinct follow-up to the OpenAI cache-write double-charge fixed there.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions