Skip to content

fix(health): probe test_connection with the credential the request names - #39801

Merged
yuneng-berri merged 5 commits into
litellm_internal_stagingfrom
litellm_health_test_connection_credential
Sep 4, 2026
Merged

fix(health): probe test_connection with the credential the request names#39801
yuneng-berri merged 5 commits into
litellm_internal_stagingfrom
litellm_health_test_connection_credential

Conversation

@yuneng-berri

@yuneng-berri yuneng-berri commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

TLDR

Problem this solves:

  • Test Connect ignored the LLM Credential you picked
  • It borrowed a key from an unrelated matching deployment
  • Wildcard routes made this hit almost every new model
  • api_base leaked the same way, redirecting the probe

How it solves it:

  • Naming a credential now blocks inheriting config credentials
  • Only the config that names the same credential still applies
  • Naming no credential keeps today's documented inheritance

User Flow

Before: an admin adding a new xAI model with a saved credential gets an auth error from Test Connect, even though the same model works once saved

  1. They open http://litellm-domain/ui/?page=models and start Add Model
  2. They pick xAI as the provider and grok-4 as the model
  3. They select their saved credential from the Existing Credentials dropdown, which hides the API key and API base fields
  4. They click Test Connect and get an authentication error naming a key they never entered
  5. The result panel echoes back the credential they picked, so nothing on screen explains the failure
  6. They save the model anyway and it works on the first real request, with no change to the credential

After: the same Test Connect passes, using the credential that was picked

  1. They open http://litellm-domain/ui/?page=models and start Add Model
  2. They pick xAI as the provider and grok-4 as the model
  3. They select their saved credential from the Existing Credentials dropdown, which hides the API key and API base fields
  4. They click Test Connect and it succeeds
  5. Saving the model still works on the first real request, as before

Relevant issues

Linear ticket

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)

Screenshots / Proof of Fix

Shared setup, both sides. A stand-in upstream on port 54711 and another on port 54712, each answering a chat completion and logging the Authorization header it received. xAI points at the first one (XAI_API_BASE is set to the 54711 one), so the second is only ever reached by inheriting the wildcard's api_base.

proxy_config.yaml, one wildcard route standing in for any deployment that matches the model string being added:

model_list:
  - model_name: xai/*
    litellm_params:
      model: xai/*
      api_key: sk-WILDCARD-KEY
      api_base: http://127.0.0.1:54712

general_settings:
  master_key: sk-1234

Store the credential the Add Model page will select:

curl -s -X POST http://127.0.0.1:54000/credentials \
  -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' \
  -d '{"credential_name":"my-xai-cred",
       "credential_values":{"api_key":"sk-CREDENTIAL-KEY-CORRECT"},
       "credential_info":{"custom_llm_provider":"xai"}}'

{"success":true,"message":"Credential created successfully"}

Before (205a5e9)

Credential selected for a new model

  1. Run the Test Connect the Add Model page sends:
curl -s -X POST http://127.0.0.1:54000/health/test_connection \
  -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' \
  -d '{"litellm_params":{"model":"xai/grok-4","custom_llm_provider":"xai",
       "litellm_credential_name":"my-xai-cred"},
       "model_info":{"mode":"chat"},"mode":"chat"}'

{"status":"success","result":{"api_base":"...:54712",...,"litellm_credential_name":"my-xai-cred",...}}
  1. Read what actually arrived upstream. The wildcard's key went on the wire and the probe was redirected to the wildcard's endpoint, while the response above named the selected credential:
UPSTREAM_HIT upstream=other-deployment path=/chat/completions authorization=Bearer sk-WILDCARD-KEY

No credential selected

  1. Same model, no credential named:
curl -s -X POST http://127.0.0.1:54000/health/test_connection \
  -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' \
  -d '{"litellm_params":{"model":"xai/grok-4","custom_llm_provider":"xai"},
       "model_info":{"mode":"chat"},"mode":"chat"}'

{"status":"success","result":{"api_base":"...:54712",...}}
  1. The configured key and endpoint are used, which is the documented behavior:
UPSTREAM_HIT upstream=other-deployment path=/chat/completions authorization=Bearer sk-WILDCARD-KEY

After (5661b20)

Credential selected for a new model

  1. The same Test Connect:
curl -s -X POST http://127.0.0.1:54000/health/test_connection \
  -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' \
  -d '{"litellm_params":{"model":"xai/grok-4","custom_llm_provider":"xai",
       "litellm_credential_name":"my-xai-cred"},
       "model_info":{"mode":"chat"},"mode":"chat"}'

{"status":"success","result":{...,"litellm_credential_name":"my-xai-cred","max_tokens":16,"cache":{"no-cache":true}}}

The borrowed api_base is gone from the echoed params.

  1. The selected credential's key went on the wire, to xAI's own base rather than the wildcard's endpoint:
UPSTREAM_HIT upstream=provider-base path=/chat/completions authorization=Bearer sk-CREDENTIAL-KEY-CORRECT

No credential selected

  1. Same model, no credential named:
curl -s -X POST http://127.0.0.1:54000/health/test_connection \
  -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' \
  -d '{"litellm_params":{"model":"xai/grok-4","custom_llm_provider":"xai"},
       "model_info":{"mode":"chat"},"mode":"chat"}'

{"status":"success","result":{"api_base":"...:54712",...}}
  1. Unchanged, still the configured key and endpoint:
UPSTREAM_HIT upstream=other-deployment path=/chat/completions authorization=Bearer sk-WILDCARD-KEY

Type

🐛 Bug Fix

Caveats (if any)

Medium

  • Naming a credential now wins over allow_client_side_credentials
  • A credential missing a region or api_version no longer borrows one

Low

  • A blank credential name still counts as naming none
  • An unknown credential name now fails auth, not "not found"
  • Results never echo a credential-resolved api_base, as before
  • Wildcard shadowing an exact-model deployment is untouched

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

/health/test_connection matches the request's model string against the
configured deployments and merges the match's litellm_params underneath the
request. A request that named a stored credential but no key of its own
still satisfied the "request sets no connection fields" test, so it inherited
the matched deployment's api_key and api_base, and load_credentials_from_list
then skipped the named credential because api_key was already set.

A wildcard route covering the model is enough to match, so the Add Model
page's Test Connect probed with an unrelated deployment's key while echoing
back the credential that was selected.

Naming a credential the configuration does not name now withholds the
configuration's credential fields, the same set already withheld from a
request that supplies its own endpoint. Naming no credential still inherits
them, as documented.
@yuneng-berri yuneng-berri added the run-ci label Sep 4, 2026 — with Claude
@codspeed-hq

codspeed-hq Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing litellm_health_test_connection_credential (5661b20) with litellm_internal_staging (300d335)

Open in CodSpeed

@greptile-apps

greptile-apps Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR makes connection tests honor the stored credential named by the request instead of inheriting credentials and endpoint settings from an unrelated model match. Requests without a named credential retain existing configuration inheritance, and deployment-by-ID probes preserve their configured endpoint. Regression tests cover wildcard matches, credential-provided endpoints, provider defaults, blank names, and existing deployments

Confidence Score: 5/5

The PR appears safe to merge because the credential inheritance fix is focused, preserves the unnamed-credential path, and has direct regression coverage

No actionable new failures remain. The previous compatibility and test-comment threads were manually resolved, and the latest changes remove the redundant test commentary without changing behavior

Important Files Changed

Filename Overview
litellm/proxy/health_endpoints/_health_endpoints.py Adds credential-aware configuration inheritance so connection probes use the request’s selected stored credential without borrowing unrelated deployment connection fields
tests/test_litellm/proxy/health_endpoints/test_health_endpoints.py Adds focused regression coverage for named credentials, wildcard deployments, blank names, provider defaults, and deployment-by-ID behavior, while removing redundant commentary

Reviews (2): Last reviewed commit: "test(health): drop test docstrings that ..." | Re-trigger Greptile

Comment thread litellm/proxy/health_endpoints/_health_endpoints.py
Comment thread tests/test_litellm/proxy/health_endpoints/test_health_endpoints.py Outdated
@codecov

codecov Bot commented Sep 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown
Contributor Author

@greptileai review


Generated by Claude Code

@yuneng-berri
yuneng-berri enabled auto-merge (squash) September 4, 2026 20:38
…l args

The connection-test regressions patched litellm.ahealth_check and read the
params handed to it. Driving the endpoint through the app with respx faking
the upstream instead lets the real credential resolution run, so the tests
assert the key and host that actually go out, which is what the bug was about.

It also drops three of the five patched proxy internals; the two that are left
are proxy-global wiring with no injection seam, the same ones the image_edit
connection test already has to reach for.
@yuneng-berri
yuneng-berri merged commit 2849aee into litellm_internal_staging Sep 4, 2026
185 of 186 checks passed
@yuneng-berri
yuneng-berri deleted the litellm_health_test_connection_credential branch September 4, 2026 21:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants