Skip to content

fix(router): stop spurious "Could not identify azure model" ERROR spam - #33620

Open
devin-ai-integration[bot] wants to merge 2 commits into
litellm_oss_daily_2026_07_16from
litellm_/azure-model-error-spam-33292
Open

fix(router): stop spurious "Could not identify azure model" ERROR spam#33620
devin-ai-integration[bot] wants to merge 2 commits into
litellm_oss_daily_2026_07_16from
litellm_/azure-model-error-spam-33292

Conversation

@devin-ai-integration

Copy link
Copy Markdown
Contributor

Relevant issues

Fixes #33172

Internal replacement branch for OSS PR #33292 by Mihidum Hettiyahandi (@mihidumh); original authorship is preserved on the commits

Linear ticket

Pre-Submission checklist

  • 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

Screenshots / Proof of Fix

This is an internal logging-noise fix in the Router's Azure base_model resolution. When an azure/ deployment's model name already resolves to a real cost-map entry, the router logged a spurious Could not identify azure model ... at ERROR on every call, which spammed logs for correctly-configured deployments

The behavior is pinned by three focused regression tests at commit 9dc23c7e3a, each of which fails on the pre-fix tree and passes here:

tests/test_litellm/test_router.py -k "azure and (base_model or resolve or cost_map or identify or fallback)"
3 passed

They cover: a known azure deployment name resolves from the cost map without an ERROR log; a genuinely unmappable name still logs the ERROR; and an explicit base_model still takes precedence

Note on live-proxy proof: reproducing the log line end-to-end needs real Azure OpenAI credentials and a deployment, which were not available in this session. The regression tests exercise the exact resolution/logging branch that changed

Type

🐛 Bug Fix

Changes

In the Azure base_model fallback path the router derives _azure_fallback_key (prefixing azure/ when missing), looks up the cost-map entry, and treats it as usable only when at least one of max_input_tokens, max_tokens, or input_cost_per_token is positive. A usable entry means the name is understood, so the message is logged at debug instead of error; genuinely unmappable names keep the original ERROR. This guards against the Router's zeroed auto-registered stubs being treated as real resolutions, and uses consistent positive checks across the gate

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

Link to Devin session: https://app.devin.ai/sessions/2a3db9e7f3234370988a77b458d0a202

mihidumh added 2 commits July 16, 2026 23:44
…oyment name resolves from the cost map

get_router_model_info already falls back to resolving the azure
deployment's model name against the model cost map when base_model is
unset — and for deployments named after real azure models (e.g.
azure/gpt-4o) that resolution returns correct max tokens and costs. The
unconditional ERROR was therefore spurious for exactly the deployments
that need no operator action, and on busy proxies it logs thousands of
times per day per multi-deployment group.

Log at debug when the fallback entry carries usable limits/costs
(membership alone is not enough: Router init auto-registers every
deployment name as a zeroed stub), keep the ERROR otherwise.

Fixes #33172
…ack gate

Review follow-up: token-limit fields used 'is not None' while the cost
field used '> 0' — a cost-map entry explicitly storing 0 limits could
suppress the error log without carrying usable resolution data. All
three checks now require a positive value.
@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

@greptile-apps

greptile-apps Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR reduces log noise in the Router's Azure base-model resolution path: when an Azure deployment's model name already exists in the cost map with real limits/costs, the previous unconditional ERROR is downgraded to DEBUG; genuinely unmappable names continue to log at ERROR.

  • The gate condition (max_input_tokens, max_tokens, or input_cost_per_token positive) is designed to reject the zeroed auto-registered stubs that Router init writes for every deployment, so only real cost-map entries suppress the error.
  • Three regression tests are added that use a local cost-map snapshot and monkeypatching to avoid network calls, covering the known-name, unknown-name, and explicit-base_model cases.

Confidence Score: 4/5

Safe to merge; the change is purely to log level and does not alter model resolution or cost-tracking behavior.

The fix is narrowly scoped to a logging branch. The only gap is that output_cost_per_token is not part of the “entry is usable” check, which could cause a known-but-zero-input-cost model to still emit the spurious ERROR, but this is an unlikely edge case for Azure models in practice.

litellm/router.py — the _fallback_resolves condition around line 8537.

Important Files Changed

Filename Overview
litellm/router.py Adds a pre-check before the existing azure base_model logging: looks up the deployment's name in the cost map and only logs at ERROR when the entry lacks usable limits/costs; known models are downgraded to DEBUG. Logic is sound; minor gap — output_cost_per_token is not included in the "usable" gate.
tests/test_litellm/test_router.py Adds three focused regression tests covering the three cases: known azure name resolves without ERROR, unmappable name still logs ERROR, and explicit base_model takes precedence. Tests use monkeypatch + local cost map to avoid network calls and isolate global state.

Reviews (1): Last reviewed commit: "fix(router): use consistent positive che..." | Re-trigger Greptile

Comment thread litellm/router.py
Comment on lines +8537 to +8541
_fallback_resolves = (
(_fallback_entry.get("max_input_tokens") or 0) > 0
or (_fallback_entry.get("max_tokens") or 0) > 0
or (_fallback_entry.get("input_cost_per_token") or 0) > 0
)

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.

P2 The _fallback_resolves gate checks max_input_tokens, max_tokens, and input_cost_per_token, but omits output_cost_per_token. A model entry that carries only a positive output_cost_per_token (zero input cost, no explicit token limit) would be misclassified as a zeroed stub and still emit the spurious ERROR. While uncommon for Azure models today, this is a latent edge-case that the same condition is supposed to guard against.

Suggested change
_fallback_resolves = (
(_fallback_entry.get("max_input_tokens") or 0) > 0
or (_fallback_entry.get("max_tokens") or 0) > 0
or (_fallback_entry.get("input_cost_per_token") or 0) > 0
)
_fallback_resolves = (
(_fallback_entry.get("max_input_tokens") or 0) > 0
or (_fallback_entry.get("max_tokens") or 0) > 0
or (_fallback_entry.get("input_cost_per_token") or 0) > 0
or (_fallback_entry.get("output_cost_per_token") or 0) > 0
)

@codecov

codecov Bot commented Jul 17, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

This one is an internal logging-noise fix in the Router's azure base_model resolution, so there is no customer-facing curl surface for the log line itself. A faithful live repro needs real Azure OpenAI creds (endpoint, key, a deployment) to drive the resolution path, and those are not available in this session, so the live log repro was not run

The behavior is pinned by 3 focused regression tests that fail before the fix and pass after: a name that resolves to a usable cost-map entry no longer logs ERROR (drops to debug), a genuinely unmappable deployment name still logs ERROR, and an explicit base_model still wins

3 passed, 119 deselected in 0.55s

regression tests

If you can drop Azure OpenAI creds into this session I can add the live log before/after as well

Full walkthrough and test report: https://app.devin.ai/sessions/2a3db9e7f3234370988a77b458d0a202

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