Skip to content

fix(ui): prevent infinite re-render loop in VirtualKeysTable - #25784

Closed
Bytechoreographer wants to merge 1 commit into
BerriAI:litellm_oss_branchfrom
Bytechoreographer:fix/virtual-keys-infinite-rerender-oss
Closed

fix(ui): prevent infinite re-render loop in VirtualKeysTable#25784
Bytechoreographer wants to merge 1 commit into
BerriAI:litellm_oss_branchfrom
Bytechoreographer:fix/virtual-keys-infinite-rerender-oss

Conversation

@Bytechoreographer

Copy link
Copy Markdown
Contributor

PR: fix(ui): prevent infinite re-render loop in VirtualKeysTable

Relevant issues

Pre-Submission checklist

  • Added tests in ui/litellm-dashboard/src/components/key_team_helpers/filter_logic.test.tsx
  • npm run test passes for affected files (34/34)
  • Scope is isolated: one source file changed, one test file updated
  • Comment @greptileai on the PR and get Confidence Score ≥ 4/5 before requesting maintainer review

Type

🐛 Bug Fix

Changes

Root cause

VirtualKeysTable.tsx passed keys?.keys || [] directly into useFilterLogic:

useFilterLogic({
  keys: keys?.keys || [],   // ← new [] literal on every render
  ...
})

While keys is loading (keys?.keys is undefined), the || [] fallback
produces a new array reference on every render. The useEffect([keys, filters])
inside useFilterLogic treats each new reference as a change, calls
setFilteredKeys, which triggers a re-render, which produces another new []
resulting in an infinite loop.

In development mode this surfaces as:

Maximum update depth exceeded.
src/components/key_team_helpers/filter_logic.tsx (102:5) @ useFilterLogic.useEffect

In the production build React's production runtime silences the warning, but
the excess re-renders still occur on every page load.

Fix

Stabilise the reference with useMemo before passing it to the hook
(VirtualKeysTable.tsx):

// Before
useFilterLogic({
  keys: keys?.keys || [],
  ...
})

// After
const keysList = useMemo(() => keys?.keys ?? [], [keys?.keys]);

useFilterLogic({
  keys: keysList,
  ...
})

useMemo returns the same [] across renders until keys?.keys actually
changes, breaking the loop. ?? is used instead of || to correctly handle
null as well as undefined.

Files changed

File Change
ui/litellm-dashboard/src/components/VirtualKeysPage/VirtualKeysTable.tsx Add useMemo to stabilise keys reference
ui/litellm-dashboard/src/components/key_team_helpers/filter_logic.test.tsx Add 2 regression tests

Tests added (filter_logic.test.tsx)

Test What it verifies
should not enter an infinite render loop when keys prop is re-rendered with a new empty-array reference Simulates the || [] pattern: calls rerender({ keys: [] }) three times; the hook must complete without hanging
should update filteredKeys when keys prop changes from empty to populated Verifies filteredKeys correctly reflects new data when keys transitions from [] to a populated array

`keys?.keys || []` produces a new array reference on every render when
`keys` is undefined (during initial load).  The useEffect([keys, filters])
in useFilterLogic treated each new reference as a change, called
setFilteredKeys, triggered a re-render, and looped indefinitely.

Stabilise the reference with useMemo before passing it to the hook:

  const keysList = useMemo(() => keys?.keys ?? [], [keys?.keys]);

Also add two regression tests in filter_logic.test.tsx that verify
the hook does not hang when re-rendered with a new empty-array reference.

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

vercel Bot commented Apr 15, 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 15, 2026 1:28pm

Request Review

@CLAassistant

CLAassistant commented Apr 15, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@greptile-apps

greptile-apps Bot commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR stabilizes the keys reference in VirtualKeysTable by wrapping keys?.keys ?? [] in useMemo, breaking an infinite re-render loop caused by useFilterLogic's useEffect([keys, filters]) re-firing every time the caller produced a new array literal. The fix is minimal, correctly targeted, and uses ?? (more precise than || for null/undefined fallback).

Confidence Score: 5/5

Safe to merge — the one-line fix is correct and the only finding is a P2 test-coverage observation.

No P0/P1 issues. The useMemo stabilization is the idiomatic React fix for this class of problem. The only concern is that the regression test exercises explicit rerenders rather than the component-level feedback cycle, so it wouldn't catch a revert of the fix — but that is a test-quality observation, not a defect in the shipped code.

No files require special attention.

Important Files Changed

Filename Overview
ui/litellm-dashboard/src/components/VirtualKeysPage/VirtualKeysTable.tsx Adds useMemo to stabilize the keys?.keys reference before passing it to useFilterLogic, correctly breaking the render-loop feedback cycle.
ui/litellm-dashboard/src/components/key_team_helpers/filter_logic.test.tsx Adds two regression tests; the first test does not reproduce the actual feedback-cycle infinite loop (it only exercises explicit rerenders, not the state-driven component re-render that triggers the real bug).

Sequence Diagram

sequenceDiagram
    participant VKT as VirtualKeysTable
    participant UFL as useFilterLogic

    note over VKT,UFL: Before fix - infinite loop while keys is loading
    VKT->>UFL: keys?.keys || [] (new ref every render)
    UFL->>UFL: useEffect fires (ref changed)
    UFL->>UFL: setFilteredKeys([])
    UFL-->>VKT: state update triggers re-render
    VKT->>UFL: keys?.keys || [] (another new ref)
    note over VKT,UFL: loop repeats indefinitely

    note over VKT,UFL: After fix - useMemo breaks the cycle
    VKT->>VKT: useMemo returns stable [] ref
    VKT->>UFL: keysList (stable ref)
    UFL->>UFL: useEffect fires once
    UFL->>UFL: setFilteredKeys([])
    UFL-->>VKT: state update triggers re-render
    VKT->>VKT: useMemo returns same [] ref (no change)
    VKT->>UFL: keysList (same ref - effect does not re-fire)
Loading

Reviews (1): Last reviewed commit: "fix(ui): prevent infinite re-render loop..." | Re-trigger Greptile

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.

3 participants