Skip to content

fix(register_model): keep bedrock geo deployments priced across price data reloads - #41523

Open
devin-ai-integration[bot] wants to merge 8 commits into
mainfrom
litellm_fix_model_cost_reload_race
Open

devin-ai-integration[bot] wants to merge 8 commits into
mainfrom
litellm_fix_model_cost_reload_race

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor

TLDR

Problem this solves:

  • A request landing mid price-data reload leaves a bedrock geo model priced at $0
  • The same collision aborts the whole reload with "dictionary changed size during iteration"
  • Every reload re-rolls it per pod, so prices flap between page refreshes

How it solves it:

  • Reload walks and lookup-map rebuilds iterate a snapshot of the cost map
  • A key the lookup cannot map inherits the matching built-in entry, prices included
  • That inheritance only spans providers the model's own lookup would accept

User Flow

Before: a proxy admin running bedrock AU geo Claude deployments on several pods sees single models lose their price on single pods after a price data reload, and those pods bill them at $0

  1. They run bedrock/au.anthropic.claude-sonnet-5 and the other AU geo Claude models as deployments on every pod, next to custom-priced deployments that take steady traffic
  2. They open https://litellm-domain/ui/?page=models and every AU model shows its input and output price, bedrock/moonshotai.kimi-k2.5 too
  3. They click Reload Price Data, which sends POST https://litellm-domain/reload/model_cost_map while requests keep flowing, and the toast says "Price data reloaded successfully! 4112 models updated."
  4. On the next refresh one pod shows "-" for au.anthropic.claude-sonnet-5 alone while kimi keeps its price, and GET https://litellm-domain/model/info on that pod returns input_cost_per_token: 0 for it
  5. They send POST https://litellm-domain/v1/chat/completions with "model": "claude-sonnet-5", get a 200 with real token usage, and GET https://litellm-domain/spend/logs?request_id= shows spend: 0.0, so the key's budget never moves
  6. They refresh https://litellm-domain/ui/?page=models again once the reload has reached the other pods and a different single model is missing there, au.anthropic.claude-opus-5 on one refresh and au.anthropic.claude-sonnet-5 on another, while kimi stays priced on every pod

After: the same reloads under the same traffic keep every AU geo model priced on every pod

  1. They run bedrock/au.anthropic.claude-sonnet-5 and the other AU geo Claude models as deployments on every pod, next to custom-priced deployments that take steady traffic
  2. They open https://litellm-domain/ui/?page=models and every AU model shows its input and output price, bedrock/moonshotai.kimi-k2.5 too
  3. They click Reload Price Data, which sends POST https://litellm-domain/reload/model_cost_map while requests keep flowing, and the toast says "Price data reloaded successfully! 4112 models updated."
  4. On the next refresh every pod still shows the AU prices, and GET https://litellm-domain/model/info returns input_cost_per_token: 2.2e-06 and output_cost_per_token: 1.1e-05 for au.anthropic.claude-sonnet-5 after every reload
  5. They send the same POST https://litellm-domain/v1/chat/completions, get a 200, and GET https://litellm-domain/spend/logs?request_id= shows spend: 0.0002486, so the key's budget keeps counting
  6. Every later refresh of https://litellm-domain/ui/?page=models on every pod shows all five AU prices, and every Reload Price Data click returns 200 with the same toast however much traffic is in flight

Relevant issues

Related: #30044 (the unmapped-key fallback this generalizes) and #30198 (the synthesized zero costs this keeps out of the map)

Affected release

Linear ticket

Resolves LIT-5853

Pre-Submission checklist

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

  • I have added meaningful tests
  • The handful of test files covering my change pass locally, e.g. uv run pytest tests/test_litellm/<your_test_file>.py -v. Leave the suites (make test-unit-*, make test-unit) to CI: it finishes in ~15 minutes where a laptop takes an hour or more
  • My PR passes all required CI/CD checks (e.g., lint, schema.d.ts sync check, etc.)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have received a Greptile Confidence Score of at least 4/5 before requesting a maintainer review (Greptile reviews automatically once the PR is opened; only comment @greptileai to re-request a review after pushing changes)

Delays in PR merge?

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

Screenshots / Proof of Fix

Verdict: FAIL. The before leg at the merge base 1dd4c13 already passes every step the User Flow predicts to fail, and the after leg at the tip 4de7bf4 (merge base d42f448) passes the same way, so this run does not prove the PR changes anything an end user can see. The mechanism the PR closes only shows in-process (last subsection), which is not end-user proof

Both legs ran the same topology: two proxy processes per leg (--num_workers 2 each, so four workers) on random ports sharing one private Postgres per leg, LITELLM_LOCAL_MODEL_COST_MAP=false with LITELLM_MODEL_COST_MAP_URL pointing at a local copy of the remote price map so every reload fetches and parses the full 4112-model catalog, the customer's five AU geo Claude deployments plus bedrock/moonshotai.kimi-k2.5 and 150 more AU geo deployments, and four custom-priced openai/gpt-5-nano deployments taking 400 concurrent real clients for the whole run. Every reload, sample, request and spend row hit the live proxies over HTTP with real Bedrock and OpenAI calls. The before leg ran on ports 36211 and 56575 with Postgres on port 60137, the after leg at 4de7bf4 on ports 37941 and 33035 with Postgres on port 30491

Each pod boots as python litellm/proxy/proxy_cli.py --config config.yaml --port <port> --host 127.0.0.1 --num_workers 2 from the leg's worktree. The reload storm is eight loops of curl -X POST http://127.0.0.1:<port>/reload/model_cost_map -H "Authorization: Bearer $KEY" (four per pod, 200 clicks each, 1,600 in total). The sampler runs four parallel curl http://127.0.0.1:<port>/model/info -H "Authorization: Bearer $KEY" per pod every second and counts AU rows whose input_cost_per_token is 0. The traffic is 400 async clients alternating POST /v1/chat/completions across both pods with "max_tokens": 16. The post-storm probe sends one real request per unified endpoint on each pod and reads back GET /spend/logs?request_id=<id>

Before (1dd4c13)

The merge base moved to d42f448 when main was merged into the branch. Its delta since 1dd4c13 leaves the registration and reload code alone (litellm/utils.py only gains the supports_mid_conversation_system helper and litellm/__init__.py only drops the use_legacy_interactions_schema flag), so this leg stands as run

Reload storm under traffic

  1. zsh storm2.sh 36211 56575 $LEG 4 200 with python3 traffic2.py 36211 56575 400 $LEG/stop_traffic running
  2. Observed (full log, traffic log):
storm2 start 22:42:15Z reloaders_per_pod=4 reloads_per_reloader=200
reload A4 1 22:42:15 status=200 {"message":"Price data reloaded successfully! 4112 models updated.","status":"success","models_count":4112,...}
...
SUMMARY reloads=1600 status200=1600 dict500=0 other_non200=0
traffic end 22:45:36Z {'ok': 14374, 'non200': 0, 'error': 151}

Models table sampled on both pods during the storm

  1. zsh sampler2.sh 36211 56575 $LEG running for the whole storm, then the Admin UI Models page of pod B after it
  2. Observed (full log): every tick shows 155 AU rows on each pod and none at $0
sample 1 22:42:15 A: au=155 samples=4 zero=0  | B: au=155 samples=4 zero=0
...
sampler end 22:45:14Z ticks=97 zero_ticks=0

pr41523-7ffe97adb7-before_models_page_poststorm_podB.png

/v1/chat/completions after the storm

  1. zsh probe.sh 36211 claude-sonnet-5 before-poststorm-podA and the same on 56575 (full output)
  2. Observed on both pods: 200 with 13 prompt and 20 completion tokens, and the spend row prices it
[before-poststorm-podA] POST /v1/chat/completions model=claude-sonnet-5 -> id prompt_tokens completion_tokens error: chatcmpl-ab405c2d-... 13 20 None
[before-poststorm-podA] GET /spend/logs?request_id=chatcmpl-ab405c2d-... -> request_id=chatcmpl-ab405c2d-... model=bedrock/au.anthropic.claude-sonnet-5 prompt_tokens=13 completion_tokens=20 spend=0.0002486
[before-poststorm-podB] POST /v1/chat/completions model=claude-sonnet-5 -> id prompt_tokens completion_tokens error: chatcmpl-66ef1d95-... 13 20 None
[before-poststorm-podB] GET /spend/logs?request_id=chatcmpl-66ef1d95-... -> request_id=chatcmpl-66ef1d95-... model=bedrock/au.anthropic.claude-sonnet-5 prompt_tokens=13 completion_tokens=20 spend=0.0002486

/v1/responses after the storm

  1. Same probe, second request
  2. Observed on both pods: 200 and a priced spend row
[before-poststorm-podA] POST /v1/responses model=claude-sonnet-5 -> id prompt_tokens completion_tokens error: resp_dg83U6CxwQ90... 13 10 None
[before-poststorm-podA] GET /spend/logs?request_id=resp_dg83U6CxwQ90... -> request_id=chatcmpl-981b5d61-... model=bedrock/au.anthropic.claude-sonnet-5 prompt_tokens=13 completion_tokens=10 spend=0.0001386
[before-poststorm-podB] POST /v1/responses model=claude-sonnet-5 -> id prompt_tokens completion_tokens error: resp_EV_LWN9NhAJL... 13 20 None
[before-poststorm-podB] GET /spend/logs?request_id=resp_EV_LWN9NhAJL... -> request_id=chatcmpl-640b9b10-... model=bedrock/au.anthropic.claude-sonnet-5 prompt_tokens=13 completion_tokens=20 spend=0.0002486

/v1/messages after the storm

  1. Same probe, third request
  2. Observed on both pods: 200 and a priced spend row
[before-poststorm-podA] POST /v1/messages model=claude-sonnet-5 -> id prompt_tokens completion_tokens error: msg_bdrk_wpstqwfiud3d... 13 10 None
[before-poststorm-podA] GET /spend/logs?request_id=msg_bdrk_wpstqwfiud3d... -> request_id=msg_bdrk_wpstqwfiud3d... model=bedrock/au.anthropic.claude-sonnet-5 prompt_tokens=13 completion_tokens=10 spend=0.0001386
[before-poststorm-podB] POST /v1/messages model=claude-sonnet-5 -> id prompt_tokens completion_tokens error: msg_bdrk_dpw7gcqy6oqs... 13 20 None
[before-poststorm-podB] GET /spend/logs?request_id=msg_bdrk_dpw7gcqy6oqs... -> request_id=msg_bdrk_dpw7gcqy6oqs... model=bedrock/au.anthropic.claude-sonnet-5 prompt_tokens=13 completion_tokens=20 spend=0.0002486

After (4de7bf4)

Reload storm under traffic

  1. zsh storm2.sh 37941 33035 $LEG 4 200 with python traffic2.py 37941 33035 400 $LEG/stop_traffic running
  2. Observed (full log, traffic log):
storm2 start 18:44:21Z reloaders_per_pod=4 reloads_per_reloader=200
reload A1 1 18:44:22 status=200 {"message":"Price data reloaded successfully! 4112 models updated.","status":"success","models_count":4112,...}
...
SUMMARY reloads=1600 status200=1600 dict500=0 other_non200=0
traffic end 18:49:53Z {'ok': 14682, 'non200': 0, 'error': 208}

Models table sampled on both pods during the storm

  1. zsh sampler2.sh 37941 33035 $LEG running for the whole storm, then the Admin UI Models page of pod B after it
  2. Observed (full log): every tick shows 155 AU rows on each pod and none at $0
sample 1 18:44:12 A: au=155 samples=4 zero=0  | B: au=155 samples=4 zero=0
...
sampler end 18:49:52Z ticks=83 zero_ticks=0

pr41523-4de7bf4ee0-after_models_page_poststorm_podB.png

/v1/chat/completions after the storm

  1. zsh probe.sh 37941 claude-sonnet-5 poststorm-A and the same on 33035 (full output)
  2. Observed on both pods: 200 with 13 prompt and 10 or 20 completion tokens, and the spend row prices it
[poststorm-A] POST /v1/chat/completions model=claude-sonnet-5 -> id prompt_tokens completion_tokens error: chatcmpl-89193125-... 13 10 None
[poststorm-A] GET /spend/logs?request_id=chatcmpl-89193125-... -> request_id=chatcmpl-89193125-... model=bedrock/au.anthropic.claude-sonnet-5 prompt_tokens=13 completion_tokens=10 spend=0.0001386
[poststorm-B] POST /v1/chat/completions model=claude-sonnet-5 -> id prompt_tokens completion_tokens error: chatcmpl-d028ac88-... 13 20 None
[poststorm-B] GET /spend/logs?request_id=chatcmpl-d028ac88-... -> request_id=chatcmpl-d028ac88-... model=bedrock/au.anthropic.claude-sonnet-5 prompt_tokens=13 completion_tokens=20 spend=0.0002486

/v1/responses after the storm

  1. Same probe, second request
  2. Observed on both pods: 200 and a priced spend row
[poststorm-A] POST /v1/responses model=claude-sonnet-5 -> id prompt_tokens completion_tokens error: resp_FPBZAzBwYwsK... 13 10 None
[poststorm-A] GET /spend/logs?request_id=resp_FPBZAzBwYwsK... -> request_id=chatcmpl-7262d99f-... model=bedrock/au.anthropic.claude-sonnet-5 prompt_tokens=13 completion_tokens=10 spend=0.0001386
[poststorm-B] POST /v1/responses model=claude-sonnet-5 -> id prompt_tokens completion_tokens error: resp_sGWqgiCxrmvw... 13 20 None
[poststorm-B] GET /spend/logs?request_id=resp_sGWqgiCxrmvw... -> request_id=chatcmpl-76d714f5-... model=bedrock/au.anthropic.claude-sonnet-5 prompt_tokens=13 completion_tokens=20 spend=0.0002486

/v1/messages after the storm

  1. Same probe, third request
  2. Observed on both pods: 200 and a priced spend row
[poststorm-A] POST /v1/messages model=claude-sonnet-5 -> id prompt_tokens completion_tokens error: msg_bdrk_gojhqcoadion... 13 10 None
[poststorm-A] GET /spend/logs?request_id=msg_bdrk_gojhqcoadion... -> request_id=msg_bdrk_gojhqcoadion... model=bedrock/au.anthropic.claude-sonnet-5 prompt_tokens=13 completion_tokens=10 spend=0.0001386
[poststorm-B] POST /v1/messages model=claude-sonnet-5 -> id prompt_tokens completion_tokens error: msg_bdrk_pcxs3adrj6ez... 13 20 None
[poststorm-B] GET /spend/logs?request_id=msg_bdrk_pcxs3adrj6ez... -> request_id=msg_bdrk_pcxs3adrj6ez... model=bedrock/au.anthropic.claude-sonnet-5 prompt_tokens=13 completion_tokens=20 spend=0.0002486

Earlier live passes, all priced throughout

Where the symptom does reproduce: in-process only, not end-user proof

The same harness against the same code, minus the proxy: a real Router with the customer's six bedrock deployments plus custom-priced openai/gpt-5-nano ones, writer threads registering the custom price the way a request does, and reloads swapping in the fetched 4112-model map. Both scripts run with PYTHONPATH at the worktree and the same arguments on both sides

Run Merge base d42f448 Tip 4de7bf4
8 writers, 3000 reloads 483 aborted reloads, 1 model left at $0 0 aborted, none at $0
16 writers, 3000 reloads 652 aborted reloads, none at $0 0 aborted, none at $0
16 async workers, real OpenAI requests, 1500 reloads 20 aborted reloads 0 aborted

The same runs at the earlier bases and tips came out the same way: 522 aborted reloads and 3 models at $0 against 0 at 7ffe97a (base, tip), and 4 async aborts against 0 at 659475d (base, tip). In a live proxy the reload runs on the event loop with the fetch and parse ahead of the swap, and 8,153 clicks across the eight logged passes, 6,400 of them under 400 concurrent clients, never landed a registration inside the walk, so the live legs cannot tell the two commits apart

Here's the User Flow that happened instead:

  1. The admin runs the five AU geo Claude deployments, kimi and 150 more AU deployments on two pods, with four custom-priced openai/gpt-5-nano deployments taking 400 concurrent clients
  2. They click Reload Price Data 1,600 times across both pods while the traffic runs, and every click returns 200 "Price data reloaded successfully! 4112 models updated." on both the merge base and the tip
  3. GET /model/info on both pods, four times a second for the whole storm, shows all 155 AU rows priced on every sample on both commits
  4. https://litellm-domain/ui/?page=models on pod B after the storm shows every AU model priced on both commits
  5. POST /v1/chat/completions, /v1/responses and /v1/messages with "model": "claude-sonnet-5" on each pod return 200, and GET /spend/logs?request_id= shows spend: 0.0002486 for 13+20 tokens (0.0001386 for 13+10) on both commits
  6. Where the User Flow predicted a "-" price, a 0 from /model/info and a spend: 0.0 row on the merge base, none appeared

Observations from the legs:

  • Transport errors at 400 clients (151 before, 208 after) are the rig, both legs alike
  • 14 shared-Postgres 500s on the first merge-base attempt: rig, not the PR
  • A custom-priced azure_ai/claude-sonnet-4-5-20250929 alias loses the cache price its shared catalog entry inherited, while its own deployment bills the same on both sides: PR causes, Decision 3, Medium caveat
  • The reload replay flips a geo row's provider to bedrock on the merge base (base); the tip keeps bedrock_converse (tip)
  • A fine-tuned openai/ft:... row never reaches pod B's /model/info: pre-existing, both legs alike

Type

🐛 Bug Fix

Caveats (if any)

High

  • No live before=fail/after=succeeds proof: the merge base already passes every step
    • the fix only shows in-process (483, 652 and 20 aborted reloads on the merge-base side, 0 on the tip)
    • closing it needs the customer's flap reproduced on a live proxy, which 8,153 logged reloads never did

Medium

Low

Final Attestation

  • The tests check the right things, including the edge cases, and regressions in the respective real-world customer use-cases are not possible after this PR

Decisions

  1. Snapshot iteration over the cost map instead of a lock: the map is a module-level dict mutated from many places, so a lock could not be enforced everywhere, while tuple(d.items()) and tuple(d) are atomic snapshots under the GIL. _handle_new_key_with_scan keeps its live walk because nothing in production calls it
  2. A key the lookup cannot map inherits the whole resolved built-in entry (tiered and above-200k prices included) next to the caller's own fields, not only its cache fields as fix(register_model): preserve built-in cache pricing when registering custom overrides under unmapped keys #30044 did, because a model that has a price in the map must never register as free; where both carry a field the caller's value wins, so a custom flat price still overrides the built-in one
  3. That inheritance is gated on the same provider check a direct lookup applies, which drops the cross-provider cache-only inheritance fix(register_model): preserve built-in cache pricing when registering custom overrides under unmapped keys #30044 allowed: a cross-provider alias such as azure/claude-sonnet-4-6 no longer picks up Anthropic's cache price and gets the "custom pricing without cache fields" warning instead. A value that names no provider is matched under its key's own provider prefix, so azure/claude-sonnet-4-6 registered without a provider never inherits Anthropic's entry (at e5ff6eb it did, litellm_provider included, and its own lookup then raised), while an openai/ft:... key now inherits its base model's entry the way a direct lookup resolves it. The key itself is the first candidate, so a catalog row registered under its own key (au.anthropic.claude-sonnet-5 from a config model_info) inherits from itself when the lookup trips, instead of from its region-stripped sibling, whose base-rate prices overwrote the geo rate at 7dbd7c0
  4. The synthesized-zero cleanup moved from after the branches into the found branch, keeping the raw entry's precedence, since only that branch can carry synthesized zeros; an inherited entry is stripped of them too, so it carries only the prices the catalogue really has
  5. The lowercase lookup map is bound locally inside the lookup so another thread's invalidation cannot null it mid-lookup
  6. The regression tests are deterministic mid-walk insertions plus one bounded router reload race, not unbounded writer threads, so they cannot go flaky or run away; the writer thread reports its failures through a queue instead of swallowing them
  7. Out of scope, filed as follow-ups: the three request-path walks over the cost map that still iterate live (ollama, fireworks, gpt-5, LIT-7953), the empty-reason 500 that POST /reload/model_cost_map returns on a remote fetch timeout (LIT-7954), and the lookup helper's catch-all that turns any error into a $0 registration (LIT-7955)
  8. Opened as a new PR: fix(utils): register_model with an empty payload silently turns unknown-model cost errors into $0.0 #36561 (draft) only covers empty registration payloads and fix(router): prevent capability leak across case-variant model registrations (#39909) #39921 is unrelated

Note

Medium Risk
Changes core model-cost registration, inheritance, and concurrent reload paths that directly drive spend tracking and budget enforcement; behavior shifts for cross-provider custom pricing (cache fields no longer auto-inherited).

Overview
Fixes $0 pricing and aborted Reload Price Data when request threads register into litellm.model_cost while the catalog is walked or the case-insensitive lookup map is rebuilt.

Concurrent reload safety: Provider-set population, lowercase-map rebuilds, and related walks now iterate tuple(...) snapshots so mid-walk inserts no longer raise dictionary changed size during iteration. Case-insensitive key resolution binds the lookup map locally so another thread’s invalidation cannot leave a lookup reading None.

Smarter built-in inheritance in register_model: When get_model_info fails or a key is unmapped, registration seeds from the matching catalog row’s full pricing (not only cache fields), with _check_provider_match so a Bedrock alias cannot pick up OpenAI prices. The registered key is tried first so geo catalog rows keep their own geo rates instead of a region-stripped sibling. _without_synthesized_costs strips helper-synthesized zero token costs so re-registration does not persist “free” models or break budget enforcement (#30198).

Regression coverage adds deterministic mid-walk tests and a bounded router reload race for Bedrock geo deployments.

Reviewed by Cursor Bugbot for commit 659475d. Bugbot is set up for automated code reviews on this repo. Configure here.

… data reloads

A request-time pricing registration inserting into litellm.model_cost while a
price data reload walked it could abort the reload (dictionary changed size
during iteration in add_known_models), or trip the lookup map rebuild inside
get_model_info so the deployment replay fell through to the unmapped path and
wrote a raw bedrock/au.anthropic.<model> entry with no token pricing, a $0
shadow re-rolled on every later reload. Walk snapshots of the map, bind the
case-insensitive lookup map locally, and let the unmapped path inherit the
whole built-in entry of a provider get_model_info would accept.
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@codspeed

codspeed Bot commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing litellm_fix_model_cost_reload_race (4de7bf4) with main (adb5ee0)1

Open in CodSpeed

Footnotes

  1. No successful run was found on main (839c040) during the generation of this report, so adb5ee0 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report. ↩

@codecov

codecov Bot commented Sep 17, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@greptile-apps

greptile-apps Bot commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

The PR appears safe to merge; no new actionable issue remains after the latest test-only update.

Summary

This PR makes model-cost registration and price-data reloads resilient to concurrent mutations, preserving built-in pricing for provider-compatible Bedrock geo aliases and preventing synthesized zero costs from becoming persistent entries.

  • Iterates mutable model-cost collections through snapshots during provider-set and lowercase-map rebuilds.
  • Keeps lowercase lookup state local during each lookup so concurrent invalidation cannot replace it mid-operation.
  • Inherits complete provider-compatible built-in pricing when registration falls through the unmapped path.
  • Adds deterministic registration, lookup-invalidation, reload-race, provider-isolation, and precedence regression coverage.

Reviews (6) · Last reviewed commit: "Merge branch 'main' of https://github.co..."

Comment thread litellm/utils.py
…lt-in pricing

An unmapped alias that inherits its built-in entry now takes only the token
prices the catalogue really carries, so a synthesized zero never lands next to
the caller's custom price. The router regression test reports the writer's
failures instead of swallowing them, and the local names carry Final.
@mateo-berri

Copy link
Copy Markdown
Contributor

@greptileai

@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

Second customer report of this race on v1.100.0 (Pylon #8731): custom priced azure_ai deployment logged $0 spend with full token counts for days. Details on LIT-5853

…m_fix_model_cost_reload_race

# Conflicts:
#	tests/test_litellm/test_router_model_cost_isolation.py
@mateo-berri

Copy link
Copy Markdown
Contributor

@greptileai

@mateo-berri

Copy link
Copy Markdown
Contributor

bugbot run

@cursor cursor Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread litellm/utils.py
@mateo-berri

Copy link
Copy Markdown
Contributor

@greptileai

@mateo-berri mateo-berri added run-ci and removed run-ci labels Sep 17, 2026
@mateo-berri

Copy link
Copy Markdown
Contributor

bugbot run

@cursor cursor Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

…t_reload_race

# Conflicts:
#	tests/test_litellm/test_utils.py
@mateo-berri

Copy link
Copy Markdown
Contributor

bugbot run

@cursor

cursor Bot commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@mateo-berri

Copy link
Copy Markdown
Contributor

@greptileai

@mateo-berri

Copy link
Copy Markdown
Contributor

bugbot run

@cursor cursor Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

…m_fix_model_cost_reload_race

# Conflicts:
#	tests/test_litellm/test_utils.py
@mateo-berri

Copy link
Copy Markdown
Contributor

@greptileai

@mateo-berri

Copy link
Copy Markdown
Contributor

bugbot run

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 4de7bf4. Configure here.

This branch has not been deployed

No deployments
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.

1 participant