Skip to content

Fix/credential list stale on add model - #26600

Closed
Bytechoreographer wants to merge 9 commits into
BerriAI:litellm_internal_stagingfrom
Bytechoreographer:fix/credential-list-stale-on-add-model
Closed

Fix/credential list stale on add model#26600
Bytechoreographer wants to merge 9 commits into
BerriAI:litellm_internal_stagingfrom
Bytechoreographer:fix/credential-list-stale-on-add-model

Conversation

@Bytechoreographer

Copy link
Copy Markdown
Contributor

PR: fix(ui): credential list stays stale on Add Model page after adding a credential


Relevant issues

Pre-Submission checklist

  • npm run test passes for affected files (5/5)
  • Scope is isolated: 4 files changed, no new dependencies
  • Comment @greptileai and get Confidence Score ≥ 4/5 before requesting maintainer review

Type

🐛 Bug Fix

Changes

Root cause

After adding, editing, or deleting a credential in the LLM Credentials tab,
the Existing Credentials dropdown on the Add Model tab does not reflect
the change until a full page refresh.

CredentialsPanel calls refetch() on its own useQuery observer after each
mutation, which refreshes the panel's own list. However, ModelsAndEndpointsView
holds a separate useCredentials() subscription and passes the result down as
credentialsList → AddModelTab → AddModelForm → AntdSelect options. That
subscription is never notified, so the dropdown stays stale:

ModelsAndEndpointsView
  └─ const { data } = useCredentials()     ← never sees the new credential
  └─ <AddModelTab credentials={credentialsList} />
       └─ <AddModelForm credentials={credentials} />
            └─ <AntdSelect options={[...credentials]} />   ← stale list

Reproduce:

  1. Open LLM Credentials tab → add a new credential
  2. Switch to Add Model tab → open the Existing Credentials dropdown
  3. Newly created credential is absent ✗
  4. Full page refresh → now it appears ✓

Fix

Replace refetch() with queryClient.invalidateQueries({ queryKey: credentialsKeys.all }),
the established cross-component cache invalidation pattern used throughout this
codebase (accessGroupKeys, projectKeys, cloudZeroSettingsKeys, keyKeys, …).

invalidateQueries marks the shared React Query cache entry as stale and triggers
a background refetch for all active subscribers — including
ModelsAndEndpointsView — so the dropdown updates immediately after any mutation.

- const { data: credentialsResponse, refetch: refetchCredentials } = useCredentials();
+ const { data: credentialsResponse } = useCredentials();
+ const queryClient = useQueryClient();

  // in each mutation handler (add / update / delete):
- await refetchCredentials();
+ await queryClient.invalidateQueries({ queryKey: credentialsKeys.all });

credentialsKeys is exported from useCredentials.ts so consumers can reference
the canonical query key without duplicating the string.

Additional fixes in the same files

credentials.tsx — remove dead Form.useForm() instance that was never
connected to any <Form form={...}>, causing the Ant Design console warning
"Instance created by useForm is not connected to any Form element".

AddModelForm.tsx — fix Ant Design console warning
"value in Select options should not be null": the "None" option used
value: null, which Ant Design v5 rejects. Changed to value: "" and removed
the corresponding initialValue={null} from Form.Item (no-selection is
correctly represented by undefined). The submit handler already deletes
litellm_credential_name from params when the value is absent, so the empty
string is handled safely.

Files changed

File Change
ui/litellm-dashboard/src/app/(dashboard)/hooks/credentials/useCredentials.ts Export credentialsKeys so consumers can reference the canonical query key
ui/litellm-dashboard/src/components/model_add/credentials.tsx Replace refetch() with invalidateQueries on all three mutation handlers; remove dead Form.useForm() + Form import
ui/litellm-dashboard/src/components/add_model/AddModelForm.tsx Fix null option value in credential AntdSelect; remove initialValue={null}
ui/litellm-dashboard/src/components/model_add/credentials.test.tsx Remove stale refetch stub; export credentialsKeys in mock; add test verifying invalidateQueries is called on credential add

Bytechoreographer and others added 8 commits April 16, 2026 14:02
…own stale

After a credential was added/updated/deleted in the "LLM Credentials" tab,
ModelsAndEndpointsView's credentialsList (passed to the "Add Model" dropdown)
was never refreshed because CredentialsPanel called refetch() on its own
observer only.

Replace with queryClient.invalidateQueries({ queryKey: credentialsKeys.all })
— the established cross-component invalidation pattern used throughout the
codebase (accessGroupKeys, projectKeys, cloudZeroSettingsKeys, etc.) — which
marks the shared React Query cache entry as stale and triggers a refetch for
all active subscribers, including ModelsAndEndpointsView.

Co-Authored-By: Claude Sonnet 4 (1M context) <noreply@anthropic.com>
keys?.keys || [] creates a fresh [] reference on every render, which
triggers useFilterLogic's useEffect (dep: keys), which calls
setFilteredKeys, which re-renders the parent, which creates another
new [] — maximum update depth exceeded.

Stabilize the reference with useMemo(() => keys?.keys ?? [], [keys])
so the effect only fires when the actual server data changes.

Co-Authored-By: Claude Sonnet 4 (1M context) <noreply@anthropic.com>
…RL in dev

The hardcoded localhost:4000 default in networking.tsx made it impossible
to run the frontend dev server against a port-forwarded K8s backend without
manually setting localStorage.

Add NEXT_PUBLIC_LITELLM_PROXY_URL as the top-level override in
defaultProxyBaseUrl. When set, all API calls (including the getUiConfig
discovery request) go to that URL. Falls back to the existing
localhost:4000 / NEXT_PUBLIC_USE_REWRITES logic unchanged.

Also fix getUiConfig to use proxyBaseUrl instead of defaultProxyBaseUrl,
so that litellm_worker_url set via localStorage is also respected for the
initial discovery request.

Co-Authored-By: Claude Sonnet 4 (1M context) <noreply@anthropic.com>
…PUBLIC_LITELLM_PROXY_URL

updateProxyBaseUrl had its own copy of the localhost:4000 fallback.
When getUiConfig received proxy_base_url=null from the backend it used
that hardcoded value, immediately overwriting the correct URL set via
NEXT_PUBLIC_LITELLM_PROXY_URL.

Fix: use the module-level defaultProxyBaseUrl (which already respects
NEXT_PUBLIC_LITELLM_PROXY_URL) as the fallback inside updateProxyBaseUrl.

Also remove the dead Form.useForm() instance in CredentialsPanel that
was never connected to any <Form form={...}>, causing the Ant Design
"Instance created by useForm is not connected" console warning.

Co-Authored-By: Claude Sonnet 4 (1M context) <noreply@anthropic.com>
Ant Design Select does not accept null as an option value.
Change { value: null, label: "None" } → { value: "", label: "None" }
and remove initialValue={null} from the Form.Item (no initial selection
is correctly represented by undefined, not null). The submit handler
already deletes litellm_credential_name from params when absent, so
the empty string is handled safely.

Co-Authored-By: Claude Sonnet 4 (1M context) <noreply@anthropic.com>
…ges from credential fix

These networking.tsx changes were only needed for the K8s port-forward
dev workflow. They are unrelated to the credential list staleness fix
and add unnecessary scope to this PR. Reverting to upstream baseline.

Co-Authored-By: Claude Sonnet 4 (1M context) <noreply@anthropic.com>
…ranch

Already covered by fix/virtual-keys-infinite-rerender. Keep credential
fix PR scope focused on the stale credential list bug only.

Co-Authored-By: Claude Sonnet 4 (1M context) <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Fixes a stale credentials dropdown on the Add Model tab. After any mutation in the LLM Credentials panel, the Existing Credentials select now updates immediately by using invalidateQueries on the shared React Query cache instead of calling refetch() on a single observer. The PR also removes a disconnected form instance and fixes a null-value warning in a Select option.

Confidence Score: 5/5

Safe to merge — targeted, well-tested fix using an established codebase pattern.

No P0 or P1 findings. The invalidateQueries prefix-match correctly covers the credentialsKeys.list({}) query key used by useCredentials. The value: "" for the "None" option is handled safely by the existing empty-string guard in the submit handler. Tests are strengthened, not weakened.

No files require special attention.

Important Files Changed

Filename Overview
ui/litellm-dashboard/src/app/(dashboard)/hooks/credentials/useCredentials.ts Exports credentialsKeys so consumers can reference the canonical query key for cross-component cache invalidation.
ui/litellm-dashboard/src/components/model_add/credentials.tsx Replaces per-observer refetch() with queryClient.invalidateQueries(credentialsKeys.all) on add/update/delete; removes dead Form.useForm() instance and Form import.
ui/litellm-dashboard/src/components/add_model/AddModelForm.tsx Changes the "None" credential option from value: null to value: "" and removes initialValue={null} to fix the Ant Design v5 warning; empty string is already correctly skipped in the submit handler.
ui/litellm-dashboard/src/components/model_add/credentials.test.tsx Removes stale refetch stubs, mocks AddCredentialModal for easier form submission in tests, and adds a new test verifying invalidateQueries is called on credential add.

Sequence Diagram

sequenceDiagram
    participant U as User
    participant CP as CredentialsPanel
    participant QC as QueryClient (shared cache)
    participant UC1 as useCredentials (CredentialsPanel)
    participant UC2 as useCredentials (ModelsAndEndpointsView)
    participant AMF as AddModelForm dropdown

    U->>CP: Add / Edit / Delete credential
    CP->>QC: invalidateQueries({ queryKey: ["credentials"] })
    QC-->>UC1: mark stale → background refetch
    QC-->>UC2: mark stale → background refetch
    UC2-->>AMF: fresh credential list
    AMF-->>U: dropdown updated ✓
Loading

Reviews (1): Last reviewed commit: "Merge branch 'BerriAI:litellm_internal_s..." | Re-trigger Greptile

@codecov

codecov Bot commented Apr 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

…e-on-add-model

# Conflicts:
#	ui/litellm-dashboard/src/components/model_add/credentials.tsx
@Bytechoreographer

Copy link
Copy Markdown
Contributor Author

@yassin-berriai @mateo-berri @Sameerlite gentle nudge on this one.

The Existing Credentials dropdown on the Add Model tab goes stale after you add, edit, or delete a credential in the LLM Credentials panel, so you have to reload the page before your change shows up. This invalidates and refetches the list so the select updates immediately.

Open since late April with no maintainer review yet. Could you take a look?

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.

2 participants