Skip to content

fix(model_management): stop persisting cost map pricing as a deployment override - #36222

Merged
ryan-crabbe-berri merged 1 commit into
litellm_internal_stagingfrom
litellm_lit_5292_model_info_pricing_filter
Sep 13, 2026
Merged

ryan-crabbe-berri merged 1 commit into
litellm_internal_stagingfrom
litellm_lit_5292_model_info_pricing_filter

Conversation

@ryan-crabbe-berri

@ryan-crabbe-berri ryan-crabbe-berri commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

TLDR

Problem this solves:

  • Saving a model in the UI pins its price forever
  • Reload Price Data then can't move that deployment
  • Nothing typed the price; the form displayed it
  • Clearing the cost fields doesn't stick across saves

How it solves it:

  • Write path drops pricing the server derived for display
  • Drop-set derived from the read path, so it can't drift
  • litellm_params stays the way to set an override

Relevant issues

Linear ticket

Resolves LIT-5292

Pre-Submission checklist

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

  • I have added meaningful tests
  • My PR passes all CI/CD checks (e.g., lint, format, unit tests)
  • 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

Type

🐛 Bug Fix

Changes

GET /model/info fills a deployment's missing pricing in from the model cost map so the Admin UI has a rate to display. Clients echo that whole model_info blob back on save, and update_db_model merged it into the row, so editing an unrelated setting turned that day's catalog price into a real per-deployment override. After that the deployment ignored the cost map, and Reload Price Data could not move it either, because the reload replays each deployment's stored pricing over the freshly fetched catalog. Clearing the cost fields worked once and then came back on the next save, since that save re-sent the same stale blob.

This drops the derived pricing from incoming model_info on POST /model/new and PATCH /model/{id}/update. The drop-set is read off the same objects the read path uses, CustomPricingLiteLLMParams plus the tiered *_above_N_tokens pattern that get_model_info passes through and no model declares, so it cannot drift as new rates are added. output_vector_size is exempt because it lives on the pricing model but is an embedding dimension rather than a rate.

Three things stay as they are. A deployment's own pricing rides litellm_params, which is untouched, so every documented way to set an override still works. The explicit-null clear still fires, because it reads the incoming model rather than the filtered dict. And the response shape is unchanged, so the form still displays the effective price.

The filter sits in the two endpoint bodies rather than in _add_model_to_db, which master-key rotation reuses to re-serialize every stored deployment; a filter there would strip the whole table on the next rotation. On the create path the blob is rebuilt from its own dump so the real deployment id rides along, since ModelInfo mints a fresh uuid when the id is absent.

Behavior changes worth calling out:

  • Setting a deployment's price by putting it in model_info on POST/PATCH no longer takes effect. That path is undeclared (ModelInfo does not declare pricing fields; they ride extra="allow") and undocumented, but it worked. Use litellm_params, which is what the Admin UI, the Terraform provider, and the lite CLI already do.
  • lite models import of a config.yaml whose model_info block carries pricing now drops that pricing on import. Move it to litellm_params in the config, or set it after import.
  • Deployments already pinned before this change stay pinned. The merge only adds, so nothing self-heals. Clearing the four cost fields in the UI still works per deployment. A cleanup path for the rest is filed separately, deliberately not a migration, since a row cannot distinguish round-trip noise from a price someone set on purpose.

Config-based models are unaffected: patch_model already rejects them, and their model_info pricing is read at boot rather than written through these endpoints.

Scoped to pricing. The same round-trip also pins mode, max_tokens, and the supports_* flags, and that half needs a replacement path for mode first, so it is a follow-up.

QA runbook

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

Note

Medium Risk
Changes which pricing fields persist on model create/update (model_info pricing is ignored; litellm_params still authoritative), which affects billing configuration and may surprise callers who set rates only in model_info.

Overview
Fixes deployments getting permanently pinned to catalog prices when the Admin UI saves a model: /model/info injects cost-map rates into model_info for display, and clients that round-trip that blob used to merge those fields into the DB as real overrides.

Write-path filtering now strips server-derived pricing from incoming model_info on PATCH (update_db_model) and POST /model/new (rebuilds ModelInfo so deployment id is preserved). The drop set lives in without_server_derived_pricing / is_server_derived_pricing_key in litellm/types/utils.py—CustomPricingLiteLLMParams fields (except output_vector_size) plus tiered *_above_*_tokens keys—aligned with what the read path can emit. litellm_params pricing is unchanged, so intentional overrides still persist there.

ABOVE_THRESHOLD_COST_KEY_PATTERN is shared with litellm/utils.py (replacing a local duplicate). Tests cover echo saves, tiered keys, exempt fields, and create-path behavior.

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

@greptile-apps

greptile-apps Bot commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR prevents pricing derived from the model cost map from being persisted as a deployment override while preserving explicit overrides in litellm_params

  • Adds a shared predicate and filter for server-derived pricing fields
  • Applies the filter when creating and updating database-backed deployments
  • Reuses the tiered-pricing key pattern from the model-info read path
  • Adds regression coverage for ordinary, tiered, explicit, and embedding-related pricing fields

Confidence Score: 5/5

The PR appears safe to merge

No blocking failure remains

Important Files Changed

Filename Overview
litellm/proxy/management_endpoints/model_management_endpoints.py Filters server-derived pricing from incoming model information on deployment create and update paths
litellm/types/utils.py Defines the shared pricing-field set, tiered-key pattern, and immutable filtering helper
litellm/utils.py Reuses the shared tiered-pricing pattern in the model-info read path
tests/test_litellm/proxy/management_endpoints/test_model_management_endpoints.py Adds regression coverage for filtering derived prices while retaining deployment identity and supported fields

Reviews (2): Last reviewed commit: "fix(model_management): stop persisting c..." | Re-trigger Greptile

Comment thread litellm/proxy/management_endpoints/model_management_endpoints.py
@codecov

codecov Bot commented Aug 7, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@codspeed

codspeed Bot commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing litellm_lit_5292_model_info_pricing_filter (76cb0fe) with litellm_internal_staging (d4a72e7)

Open in CodSpeed

@devin-ai-integration

Copy link
Copy Markdown
Contributor

Removed the new inline comments in the endpoint, types, and tests; context now lives in docstrings and the PR description.

@CLAassistant

CLAassistant commented Sep 2, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

…nt override

/model/info fills a deployment's missing pricing in from the model cost map so the
Admin UI has a rate to display. Clients echo that whole model_info blob back on save,
and update_db_model merged it into the row, so editing an unrelated setting turned
that day's catalog price into a real per-deployment override. After that the
deployment ignored the cost map and Reload Price Data could no longer move it,
because the reload replays each deployment's stored pricing over the fresh catalog.

Drop the derived pricing from incoming model_info on the two write paths. The
drop-set is read off the same objects the read path uses, CustomPricingLiteLLMParams
plus the tiered *_above_N_tokens pattern that get_model_info passes through and no
model declares, so it cannot drift as new rates are added. output_vector_size is
exempt: it lives on the pricing model but is an embedding dimension, not a rate.

A deployment's own pricing still rides litellm_params, which is untouched, as is the
explicit-null clear, which reads the incoming model rather than the filtered dict.
The filter sits in the endpoint bodies rather than _add_model_to_db, which master-key
rotation reuses to re-serialize every stored deployment.
@ryan-crabbe-berri
ryan-crabbe-berri force-pushed the litellm_lit_5292_model_info_pricing_filter branch from 5a1ec6e to 76cb0fe Compare September 13, 2026 00:30
@ryan-crabbe-berri
ryan-crabbe-berri requested a review from a team September 13, 2026 00:30
@ryan-crabbe-berri

Copy link
Copy Markdown
Contributor Author

@greptileai re review

@ryan-crabbe-berri

Copy link
Copy Markdown
Contributor Author

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 76cb0fe. Configure here.

@ryan-crabbe-berri
ryan-crabbe-berri merged commit a969319 into litellm_internal_staging Sep 13, 2026
97 checks passed
@ryan-crabbe-berri
ryan-crabbe-berri deleted the litellm_lit_5292_model_info_pricing_filter branch September 13, 2026 01:16
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.

3 participants