litellm - ✅(Solved) Fix [Bug]: Anthropic /v1/messages passthrough cost tracking ignores actual router model_id pricing [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
BerriAI/litellm#28228Fetched 2026-05-20 03:40:50
View on GitHub
Comments
0
Participants
1
Timeline
3
Reactions
0
Participants
Timeline (top)
labeled ×2cross-referenced ×1

Fix Action

Fixed

PR fix notes

PR #28229: fix: use router deployment id for anthropic messages cost

Description (problem / solution / changelog)

Relevant issues

Fixes #28228

Linear ticket

N/A

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have Added testing in the tests/test_litellm/ directory, Adding at least 1 test is a hard requirement - see details
  • My PR passes all unit tests on make test-unit
    • Not run locally; scoped tests below were run instead.
  • My PR's scope is as isolated as possible, it only solves 1 specific problem
  • I have requested a Greptile review by commenting @greptileai and received a Confidence Score of at least 4/5 before requesting a maintainer review

Delays in PR merge?

If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).

CI (LiteLLM team)

CI status guideline:

  • 50-55 passing tests: main is stable with minor issues.
  • 45-49 passing tests: acceptable but needs attention
  • <= 40 passing tests: unstable; be careful with your merges and assess the risk.
  • Branch creation CI run
    Link:

  • CI run for the last commit
    Link:

  • Merge / cherry-pick CI run
    Links:

Screenshots / Proof of Fix

Scoped local verification:

python3 -m py_compile litellm/litellm_core_utils/litellm_logging.py litellm/proxy/pass_through_endpoints/llm_provider_handlers/anthropic_passthrough_logging_handler.py litellm/proxy/common_request_processing.py tests/test_litellm/litellm_core_utils/test_litellm_logging.py tests/test_litellm/proxy/test_common_request_processing.py
# passed

git diff --check
# passed

uv run pytest tests/test_litellm/litellm_core_utils/test_litellm_logging.py -k 'router_model_id or custom_pricing or AnthropicPassthroughCustomPricing or direct_model_info' -q
# 9 passed, 73 deselected

uv run --extra proxy pytest tests/test_litellm/proxy/test_common_request_processing.py -k 'response_cost or get_custom_headers' -q
# 8 passed, 80 deselected

uv run black --check litellm/litellm_core_utils/litellm_logging.py litellm/proxy/common_request_processing.py litellm/proxy/pass_through_endpoints/llm_provider_handlers/anthropic_passthrough_logging_handler.py tests/test_litellm/litellm_core_utils/test_litellm_logging.py tests/test_litellm/proxy/test_common_request_processing.py
# passed

uv run ruff check litellm/litellm_core_utils/litellm_logging.py litellm/proxy/common_request_processing.py litellm/proxy/pass_through_endpoints/llm_provider_handlers/anthropic_passthrough_logging_handler.py
# passed

uv run ruff check over the full touched test files was not used as a pass/fail signal because tests/test_litellm/litellm_core_utils/test_litellm_logging.py currently has pre-existing lint violations unrelated to this change.

Type

🐛 Bug Fix ✅ Test

Changes

This fixes Anthropic native /v1/messages cost tracking when several router deployments share the same public model group but have deployment-specific custom pricing.

  • Prefer direct litellm_params["model_info"].id when resolving the router deployment id for cost lookup, before falling back to litellm_metadata / metadata.
  • Detect custom pricing in direct litellm_params["model_info"], not only nested metadata.
  • Preserve calculated response cost in hidden params after the logging cost calculator runs, so proxy headers/spend can use the same cost.
  • Pass the logging object into Anthropic passthrough completion_cost() and store the calculated response cost on model_call_details, matching other passthrough handlers.
  • Fall back to litellm_logging_obj.model_call_details["response_cost"] in proxy custom headers when response hidden params do not contain a cost yet.
  • Add regression coverage for two deployments under one public model group with different custom pricing, verifying cost uses the selected deployment id.

Changed files

  • litellm/litellm_core_utils/litellm_logging.py (modified, +22/-3)
  • litellm/proxy/common_request_processing.py (modified, +7/-0)
  • litellm/proxy/pass_through_endpoints/llm_provider_handlers/anthropic_passthrough_logging_handler.py (modified, +2/-0)
  • tests/test_litellm/litellm_core_utils/test_litellm_logging.py (modified, +106/-0)
  • tests/test_litellm/proxy/test_common_request_processing.py (modified, +36/-0)

Code Example

model_list:
  - model_name: claude-public
    litellm_params:
      model: anthropic/provider-a-model
      api_base: https://provider-a.example.invalid
      api_key: os.environ/PROVIDER_A_API_KEY
    model_info:
      id: provider-a-deployment-id
      input_cost_per_token: 0.000001
      output_cost_per_token: 0.000002

  - model_name: claude-public
    litellm_params:
      model: anthropic/provider-b-model
      api_base: https://provider-b.example.invalid
      api_key: os.environ/PROVIDER_B_API_KEY
    model_info:
      id: provider-b-deployment-id
      input_cost_per_token: 0.000003
      output_cost_per_token: 0.000004
RAW_BUFFERClick to expand / collapse

What happened?

Anthropic native /v1/messages cost tracking can use the wrong custom price when multiple router deployments share the same public model_name.

In this setup, the proxy response header x-litellm-model-id shows the actual selected deployment id, but x-litellm-response-cost-original / spend can be calculated with another deployment's custom pricing from the same public model group.

This affects Anthropic Messages clients that call LiteLLM with the Anthropic-native API shape instead of /chat/completions.

Expected behavior

Cost tracking should use the actual router-selected deployment model_info.id and that deployment's custom pricing for /v1/messages, including passthrough/non-streaming paths. The deployment id used for x-litellm-model-id should match the deployment id used for custom pricing lookup.

Actual behavior

When two deployments share one public model group but have different model_info custom pricing, a /v1/messages request can be routed to provider-b while response cost/spend is calculated using provider-a's pricing.

Minimal config shape

model_list:
  - model_name: claude-public
    litellm_params:
      model: anthropic/provider-a-model
      api_base: https://provider-a.example.invalid
      api_key: os.environ/PROVIDER_A_API_KEY
    model_info:
      id: provider-a-deployment-id
      input_cost_per_token: 0.000001
      output_cost_per_token: 0.000002

  - model_name: claude-public
    litellm_params:
      model: anthropic/provider-b-model
      api_base: https://provider-b.example.invalid
      api_key: os.environ/PROVIDER_B_API_KEY
    model_info:
      id: provider-b-deployment-id
      input_cost_per_token: 0.000003
      output_cost_per_token: 0.000004

Reproduction logic

  1. Configure two deployments with the same public model_name and different model_info.id + custom pricing.
  2. Send a non-streaming Anthropic Messages request to /v1/messages with model: claude-public.
  3. Force or observe a request selecting provider-b.
  4. Compare x-litellm-model-id against x-litellm-response-cost-original / spend logs.

Expected: selected provider-b deployment id and provider-b custom pricing are used together.

Actual: selected deployment id can be provider-b, while response cost/spend uses provider-a pricing.

What part of LiteLLM is this about?

Proxy

LiteLLM version

Observed on v1.82.6. The affected code path is still relevant on litellm_internal_staging.

Related issues / PRs checked

Related but not identical:

  • #11975: custom pricing in model_info not applied for cost tracking
  • #23309: custom pricing not applied for anthropic_messages with azure_ai
  • #24204: spend not tracked for anthropic_messages and passthrough call types
  • #24080 / #23239: previous custom pricing fixes for /v1/messages and /v1/responses

This issue is specifically about selecting deployment-specific pricing using the actual router deployment id when several deployments share one public model group.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

Cost tracking should use the actual router-selected deployment model_info.id and that deployment's custom pricing for /v1/messages, including passthrough/non-streaming paths. The deployment id used for x-litellm-model-id should match the deployment id used for custom pricing lookup.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING