Skip to content

fix(dashscope): treat an explicit 0.0 tier cost as a real price, not missing - #30749

Merged
Sameerlite merged 1 commit into
BerriAI:litellm_oss_staging_230626from
devYRPauli:fix/dashscope-tiered-zero-cost-v2
Jun 23, 2026
Merged

fix(dashscope): treat an explicit 0.0 tier cost as a real price, not missing#30749
Sameerlite merged 1 commit into
BerriAI:litellm_oss_staging_230626from
devYRPauli:fix/dashscope-tiered-zero-cost-v2

Conversation

@devYRPauli

Copy link
Copy Markdown
Contributor

Re-submit of #30653, which was merged then reverted from litellm_internal_staging because the previous Optional[str] annotation pushed the UP045 count over the ceiling in ruff-strict-budget.json. This version uses the X | None style so it adds no new UP045 violations (count on the file stays at the pre-existing 3).

Bug

_calculate_tiered_cost resolved a tier's per-token rate with:

cost_per_token = tier.get(cost_key) or tier.get(fallback_cost_key, 0)

The or short-circuits on a falsy 0.0, so a tier that legitimately prices cached reads (or reasoning tokens) at 0.0 (e.g. a free-cache-read tier) is silently billed at the full fallback rate. This happens at both the in-range and the overflow (beyond-highest-tier) sites.

Fix

Add _resolve_tier_cost_per_token, which only falls back when the primary key is absent (is None), treating an explicit 0.0 as a real price. This mirrors the flat-pricing path in _calculate_prompt_cost / _calculate_completion_cost, which already guards with is None.

Tests

Two new tests cover the in-range and overflow paths with a 0.0 cache-read tier, asserting the cost is 0.0 and not the input rate. Full dashscope cost-calculator suite passes locally and ruff is clean.

…missing

_calculate_tiered_cost resolved a tier's per-token rate with
`tier.get(cost_key) or tier.get(fallback_cost_key, 0)`. The `or`
short-circuits on a falsy 0.0, so a tier that legitimately prices cached
reads (or reasoning tokens) at 0.0 was silently billed at the full
fallback rate, at both the in-range and overflow sites.

Add _resolve_tier_cost_per_token, which only falls back when the primary
key is absent (is None), mirroring the flat-pricing path that already
guards correctly. Uses the X | None annotation style to stay within the
ruff strict-rule budget.

Re-submit of BerriAI#30653, which was reverted from litellm_internal_staging
because the previous Optional[str] annotation pushed the UP045 count over
the ruff-strict-budget.json ceiling.
@greptile-apps

greptile-apps Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a billing correctness bug in the Dashscope tiered cost calculator where a tier's explicit 0.0 price (e.g. a free-cache-read tier) was silently treated as "missing" due to Python's falsy or short-circuit, causing cached tokens to be charged at the full input rate instead.

  • Introduces _resolve_tier_cost_per_token, which falls back to the secondary key only when the primary key is absent (is None), aligning tiered pricing with the existing flat-pricing logic in _calculate_prompt_cost / _calculate_completion_cost.
  • Replaces both or-based cost lookups in _calculate_tiered_cost (in-range and overflow paths) with calls to the new helper.
  • Adds two focused unit tests covering zero-cost in-range and overflow scenarios with no real network calls.

Confidence Score: 5/5

The change is a narrowly scoped fix to a single billing helper with clear before/after semantics and no effect on other providers or the hot request path.

The logic switch from or-based to is None-based fallback is correct, well-tested with two new unit tests, and consistent with how the flat-pricing path already works in the same file. The helper is small and its behavior is fully covered for the zero-cost case in both the in-range and overflow branches.

No files require special attention.

Important Files Changed

Filename Overview
litellm/llms/dashscope/cost_calculator.py Adds _resolve_tier_cost_per_token helper that correctly treats an explicit 0.0 as a real price by using an is None guard instead of the falsy or short-circuit; both the in-range and overflow billing sites are updated to use it.
tests/test_litellm/llms/dashscope/test_dashscope_cost_calculator.py Adds two pure unit tests (no network calls) directly exercising _calculate_tiered_cost for the zero-cost in-range and overflow paths; removes an unused json import.

Reviews (1): Last reviewed commit: "fix(dashscope): treat an explicit 0.0 ti..." | Re-trigger Greptile

@codecov

codecov Bot commented Jun 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.71429% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
litellm/llms/dashscope/cost_calculator.py 85.71% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@Sameerlite
Sameerlite changed the base branch from litellm_internal_staging to litellm_oss_staging_230626 June 23, 2026 13:30
@Sameerlite
Sameerlite merged commit aed763b into BerriAI:litellm_oss_staging_230626 Jun 23, 2026
75 checks passed
Sameerlite pushed a commit that referenced this pull request Jun 24, 2026
…missing (#30749)

_calculate_tiered_cost resolved a tier's per-token rate with
`tier.get(cost_key) or tier.get(fallback_cost_key, 0)`. The `or`
short-circuits on a falsy 0.0, so a tier that legitimately prices cached
reads (or reasoning tokens) at 0.0 was silently billed at the full
fallback rate, at both the in-range and overflow sites.

Add _resolve_tier_cost_per_token, which only falls back when the primary
key is absent (is None), mirroring the flat-pricing path that already
guards correctly. Uses the X | None annotation style to stay within the
ruff strict-rule budget.

Re-submit of #30653, which was reverted from litellm_internal_staging
because the previous Optional[str] annotation pushed the UP045 count over
the ruff-strict-budget.json ceiling.
Sameerlite pushed a commit that referenced this pull request Jun 29, 2026
…missing (#30749)

_calculate_tiered_cost resolved a tier's per-token rate with
`tier.get(cost_key) or tier.get(fallback_cost_key, 0)`. The `or`
short-circuits on a falsy 0.0, so a tier that legitimately prices cached
reads (or reasoning tokens) at 0.0 was silently billed at the full
fallback rate, at both the in-range and overflow sites.

Add _resolve_tier_cost_per_token, which only falls back when the primary
key is absent (is None), mirroring the flat-pricing path that already
guards correctly. Uses the X | None annotation style to stay within the
ruff strict-rule budget.

Re-submit of #30653, which was reverted from litellm_internal_staging
because the previous Optional[str] annotation pushed the UP045 count over
the ruff-strict-budget.json ceiling.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants