Skip to content

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

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

fix(ui): credential list stays stale on Add Model page after adding a credential#25851
Bytechoreographer wants to merge 7 commits into
BerriAI:litellm_oss_branchfrom
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

Branch: Bytechoreographer:fix/credential-list-stale-on-add-model
Target: BerriAI:litellm_oss_branch
PR link: https://github.com/Bytechoreographer/litellm/pull/new/fix/credential-list-stale-on-add-model


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 7 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>
@vercel

vercel Bot commented Apr 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
litellm Ready Ready Preview, Comment Apr 16, 2026 10:07am

Request Review

@greptile-apps

greptile-apps Bot commented Apr 16, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Fixes a bug where the Existing Credentials dropdown on the Add Model tab stayed stale after mutations in the LLM Credentials panel. CredentialsPanel was calling refetch() on its own observer, leaving the shared React Query cache entry unnotified. The patch exports credentialsKeys and uses queryClient.invalidateQueries in all three mutation handlers, which triggers a background refetch for every active subscriber. Two Ant Design console warnings are also resolved: a disconnected form instance and a null Select option value.

Confidence Score: 5/5

Safe to merge — the fix is minimal, follows established patterns in this codebase, and all remaining findings are P2 or lower.

The invalidation approach is the canonical React Query cross-component pattern already used throughout the codebase. The empty-string Select value is correctly handled by the existing skip-guard in the submit handler. No P0 or P1 issues found.

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 ["credentials"] prefix for cache invalidation without duplicating the string literal.
ui/litellm-dashboard/src/components/model_add/credentials.tsx Replaces all three local refetch calls with invalidateQueries on the shared cache prefix; removes the disconnected Form.useForm instance. Straightforward and correct.
ui/litellm-dashboard/src/components/add_model/AddModelForm.tsx Changes the None option value from null to empty string and removes initialValue={null}; the submit handler already skips empty-string values at line 54, so no credential is sent when None is selected.
ui/litellm-dashboard/src/components/model_add/credentials.test.tsx Mocks AddCredentialModal to bypass Ant Design form internals, removes stale refetch stub, adds a focused test asserting invalidateQueries is called with ["credentials"] after a credential add.

Sequence Diagram

sequenceDiagram
    participant CP as CredentialsPanel
    participant QC as QueryClient
    participant MAV as ModelsAndEndpointsView
    participant API as Backend

    Note over CP,MAV: Before fix
    CP->>API: create credential
    CP->>CP: refetch (local only)
    MAV-->>MAV: stale list remains

    Note over CP,MAV: After fix
    CP->>API: create credential
    CP->>QC: invalidateQueries(credentialsKeys.all)
    QC->>API: refetch for CredentialsPanel subscriber
    QC->>API: refetch for ModelsAndEndpointsView subscriber
    MAV-->>MAV: updated list received
Loading

Reviews (1): Last reviewed commit: "revert(ui): remove VirtualKeysTable useM..." | Re-trigger Greptile

@Sameerlite
Sameerlite deleted the branch BerriAI:litellm_oss_branch April 27, 2026 04:56
@Sameerlite Sameerlite closed this Apr 27, 2026
@Bytechoreographer

Copy link
Copy Markdown
Contributor Author

@Sameerlite Is this issue fixed by someone else? Or should I change the branch and make another pull request?

@Sameerlite

Copy link
Copy Markdown
Contributor

Sorry about that, can you please reraise this with litellm_internal_staging branch as base?

@Bytechoreographer

Copy link
Copy Markdown
Contributor Author

@Sameerlite #26600 Here is the new pr. #25784 this pr is also closed earlier, and here is the new one
#26601

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