Skip to content

fix(litellm): fall back to /v1/models if /v1/model/info is forbidden#855

Closed
richard-guan-dev wants to merge 3 commits into
Zoo-Code-Org:mainfrom
richard-guan-dev:fix/litellm-virtual-key-403
Closed

fix(litellm): fall back to /v1/models if /v1/model/info is forbidden#855
richard-guan-dev wants to merge 3 commits into
Zoo-Code-Org:mainfrom
richard-guan-dev:fix/litellm-virtual-key-403

Conversation

@richard-guan-dev

@richard-guan-dev richard-guan-dev commented Jul 7, 2026

Copy link
Copy Markdown

On LiteLLM instances using virtual keys, the metadata endpoint /v1/model/info is restricted and returns a 403 Forbidden error. This PR adds a fallback mechanism that queries the standard /v1/models endpoint instead to list available models, parsing the simpler payload correctly.

Summary by CodeRabbit

  • Bug Fixes
    • Improved LiteLLM model loading by retrying with a fallback endpoint when the primary request is forbidden.
    • Added more resilient parsing for differing LiteLLM response shapes across endpoints.
    • If both requests fail, the original primary error is preserved for clearer troubleshooting.
  • Tests
    • Expanded unit coverage to verify fallback behavior, correct handling of edge-case failures, and proper error propagation.

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c07a8d1d-952a-4494-afef-45c86bfca99a

📥 Commits

Reviewing files that changed from the base of the PR and between 3594d16 and 1d6b53c.

📒 Files selected for processing (1)
  • src/api/providers/fetchers/__tests__/litellm.spec.ts

📝 Walkthrough

Walkthrough

getLiteLLMModels now retries /v1/models when /v1/model/info returns HTTP 403, parses fallback and non-fallback responses differently, and includes tests for successful fallback, fallback failure, non-403 error handling, and fallback parsing edge cases.

Changes

LiteLLM Model Fetching Fallback

Layer / File(s) Summary
Fallback request flow and error propagation
src/api/providers/fetchers/litellm.ts
Adds an initial /v1/model/info request, retries /v1/models on HTTP 403, and rethrows the original error if the fallback request fails.
Dual response parsing
src/api/providers/fetchers/litellm.ts
Parses fallback responses from response.data.data id entries with defaulted fields, and non-fallback responses from model_name/model_info with computed limits, flags, and pricing.
Fallback flow tests
src/api/providers/fetchers/__tests__/litellm.spec.ts
Adds tests covering fallback success, fallback failure using the original error message, non-403 errors that do not trigger fallback, and fallback parsing edge cases.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant getLiteLLMModels
  participant ModelInfoEndpoint as /v1/model/info
  participant ModelsEndpoint as /v1/models

  Caller->>getLiteLLMModels: request models
  getLiteLLMModels->>ModelInfoEndpoint: GET model info
  alt success
    ModelInfoEndpoint-->>getLiteLLMModels: model_name/model_info response
    getLiteLLMModels->>getLiteLLMModels: parse non-fallback branch
    getLiteLLMModels-->>Caller: return model map
  else HTTP 403
    ModelInfoEndpoint-->>getLiteLLMModels: error
    getLiteLLMModels->>ModelsEndpoint: GET fallback models
    alt fallback success
      ModelsEndpoint-->>getLiteLLMModels: id-based response
      getLiteLLMModels->>getLiteLLMModels: parse fallback branch
      getLiteLLMModels-->>Caller: return model map
    else fallback failure
      ModelsEndpoint-->>getLiteLLMModels: error
      getLiteLLMModels-->>Caller: reject with original error
    end
  else non-403 error
    ModelInfoEndpoint-->>getLiteLLMModels: error
    getLiteLLMModels-->>Caller: reject immediately
  end
Loading

Suggested labels: awaiting-review

Suggested reviewers: taltas, JamesRobert20, navedmerchant

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description only states the fix and misses the required issue link, test procedure, checklist, and other template sections. Add the linked issue, a fuller implementation summary, test steps, checklist items, and any relevant notes per the template.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: falling back to /v1/models when /v1/model/info is forbidden.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Jul 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 86.84211% with 5 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/api/providers/fetchers/litellm.ts 86.84% 0 Missing and 5 partials ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai 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.

🧹 Nitpick comments (1)
src/api/providers/fetchers/litellm.ts (1)

35-48: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Fallback triggers on any error and swallows the fallback failure.

Two related concerns in the retry block:

  1. The catch (infoError) fires the fallback for any failure (network error, timeout, 500, etc.), not just the 403 this PR targets. A transient /v1/model/info error will now silently return degraded models (default capabilities, no pricing) instead of surfacing the failure. Consider gating the fallback on a 403 status.
  2. fallbackError is caught but never logged before throw infoError, so when /v1/models also fails there's no visibility into why the fallback failed.
♻️ Suggested narrowing + logging
 	} catch (infoError: any) {
+		// Only fall back for authorization failures (e.g. virtual keys blocked on /v1/model/info)
+		if (infoError?.response?.status !== 403) {
+			throw infoError
+		}
 		console.warn(
 			`[getLiteLLMModels] Failed to fetch /v1/model/info, attempting fallback to /v1/models:`,
 			infoError.message,
 		)
 		const fallbackUrlObj = new URL(baseUrl)
 		fallbackUrlObj.pathname = fallbackUrlObj.pathname.replace(/\/+$/, "").replace(/\/+/g, "/") + "/v1/models"
 		const fallbackUrl = fallbackUrlObj.href
 		try {
 			response = await axios.get(fallbackUrl, { headers, timeout: 5000 })
 			isFallback = true
 		} catch (fallbackError: any) {
+			console.warn(`[getLiteLLMModels] Fallback to /v1/models also failed:`, fallbackError.message)
 			throw infoError
 		}
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/providers/fetchers/litellm.ts` around lines 35 - 48, Narrow the
LiteLLM fallback in getLiteLLMModels so it only runs for the intended 403 case
from /v1/model/info, rather than for every infoError; inspect the error status
before building fallbackUrl and calling axios.get. Also, in the fallback catch
block, log fallbackError with the existing console.warn/console.error context
before rethrowing so failures in /v1/models are visible instead of silently
bubbling as infoError.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/api/providers/fetchers/litellm.ts`:
- Around line 35-48: Narrow the LiteLLM fallback in getLiteLLMModels so it only
runs for the intended 403 case from /v1/model/info, rather than for every
infoError; inspect the error status before building fallbackUrl and calling
axios.get. Also, in the fallback catch block, log fallbackError with the
existing console.warn/console.error context before rethrowing so failures in
/v1/models are visible instead of silently bubbling as infoError.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 943030f3-1bcd-4ead-8f07-2ff00e593448

📥 Commits

Reviewing files that changed from the base of the PR and between ff3730a and 1ca9f06.

📒 Files selected for processing (2)
  • src/api/providers/fetchers/__tests__/litellm.spec.ts
  • src/api/providers/fetchers/litellm.ts

@richard-guan-dev richard-guan-dev deleted the fix/litellm-virtual-key-403 branch July 7, 2026 05:46
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