Skip to content

fix(proxy): load REDIS_* env vars when cache_params has non-connection keys#26576

Open
dschulmeist wants to merge 1 commit into
BerriAI:litellm-oss-staging-04-25-2026from
dschulmeist:fix/redis-env-vars-cache-params-26233
Open

fix(proxy): load REDIS_* env vars when cache_params has non-connection keys#26576
dschulmeist wants to merge 1 commit into
BerriAI:litellm-oss-staging-04-25-2026from
dschulmeist:fix/redis-env-vars-cache-params-26233

Conversation

@dschulmeist

Copy link
Copy Markdown

Re-opening previously closed PR #26244 against the new OSS staging branch (the original target litellm_oss_branch was deleted on 2026-04-27 as part of the maintainer branch rotation).

Relevant issues

Fixes #26233

Type

Bug Fix

Problem

In `ProxyConfig.load_config`, the Redis env-var fallback was gated on `len(cache_params.keys()) == 0`. A config like `cache_params: {mode: default_off}` plus `REDIS_HOST` env vars silently fell back to InMemoryCache because `mode` made cache_params non-empty, skipping the env-var branch. Downstream, `spend_counter_cache.redis_cache` stays `None` and per-pod counters diverge — breaks spend tracking in multi-pod deployments.

Fix

Replace the length check with a "no connection details supplied" check:
```python
if (cache_type == "redis" or cache_type == "redis-semantic") and (
"host" not in cache_params and "url" not in cache_params
):
```

Other cache_params keys (`mode`, `ttl`, etc.) no longer suppress the env-var fallback.

Tests

Two new tests in `tests/test_litellm/proxy/test_proxy_server.py`:

  1. `test_redis_env_vars_loaded_when_cache_params_has_non_connection_keys` — regression test
  2. `test_explicit_cache_params_host_not_overwritten_by_env_vars` — guards env vars from clobbering explicit `host`

Both fail on the base branch without the fix and pass with it.

Pre-Submission checklist

  • Added testing in `tests/test_litellm/`
  • PR passes touched-file tests
  • Scope isolated to a single bug

…n keys (BerriAI#26233)

The cache_params env-var fallback in ProxyConfig.load_config was gated on
`len(cache_params.keys()) == 0`, so any non-empty cache_params (e.g. just
`mode: default_off`) silently dropped the Redis env var config and fell
back to in-memory cache. This broke multi-pod deployments because
spend_counter_cache.redis_cache never got wired up and each pod tracked
counters independently.

Replace the length check with a "user did not supply connection details"
check: only populate REDIS_HOST / REDIS_PORT / REDIS_PASSWORD from the
environment when neither `host` nor `url` is present in cache_params.
Other cache_params keys (mode, ttl, etc.) no longer suppress the fallback.

Adds two regression tests exercising ProxyConfig.load_config:
- cache_params with only non-connection keys → env vars load, RedisCache path
- cache_params with explicit host → env vars do not overwrite user config

Fixes BerriAI#26233
@greptile-apps

greptile-apps Bot commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a silent fallback-to-in-memory-cache bug in ProxyConfig.load_config where any non-connection key in cache_params (e.g. mode: default_off) caused the REDIS_* env-var fallback to be skipped, breaking spend tracking in multi-pod deployments. The fix replaces the empty-length guard with a precise "no connection details supplied" check, and two new mock-only regression tests are added that cleanly cover the regression and the guard-against-overwrite cases.

Confidence Score: 4/5

Safe to merge — the fix is minimal, correct, and well-tested; only a minor test-coverage gap remains.

P2-only finding (missing url-key test for the companion guard test). The production code change is a single-condition replacement with no regression risk, and existing tests properly mock all network calls.

No files require special attention.

Important Files Changed

Filename Overview
litellm/proxy/proxy_server.py Fixes the env-var fallback gate from len(cache_params) == 0 to a "no connection keys" check (host/url absent); minimal, targeted change with good inline comment.
tests/test_litellm/proxy/test_proxy_server.py Adds two new mock-only regression tests that correctly exercise the fix; minor gap — no test covers the url connection-key bypass path.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[load_config: cache true] --> B{cache_params provided?}
    B -- yes --> C[merge cache_params_in_config]
    B -- no --> D[cache_params is empty dict]
    C --> E{cache_type is redis or redis-semantic?}
    D --> E
    E -- no --> J[_init_cache with params as-is]
    E -- yes --> F{host not in cache_params AND url not in cache_params?}
    F -- true --> G[Load REDIS_HOST / REDIS_PORT / REDIS_PASSWORD from env]
    G --> H[Update cache_params with env values]
    H --> J
    F -- false --> I[Use cache_params connection details as supplied]
    I --> J[_init_cache with cache_params]
Loading

Reviews (1): Last reviewed commit: "fix(proxy): load REDIS_* env vars when c..." | Re-trigger Greptile

Comment on lines +5147 to +5194
@pytest.mark.asyncio
async def test_explicit_cache_params_host_not_overwritten_by_env_vars(monkeypatch):
"""
Companion to test_redis_env_vars_loaded_when_cache_params_has_non_connection_keys.

When `cache_params` explicitly specifies a `host`, the REDIS_* env vars
must NOT overwrite it. The env-var fallback only applies when the user
has supplied no connection details.
"""
import tempfile

from litellm.proxy.proxy_server import ProxyConfig

monkeypatch.setenv("REDIS_HOST", "env-redis.internal")
monkeypatch.setenv("REDIS_PORT", "6379")

test_config = {
"model_list": [],
"router_settings": {},
"litellm_settings": {
"cache": True,
"cache_params": {
"host": "explicit-redis.internal",
"port": 1234,
"mode": "default_off",
},
},
}

with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f:
yaml.dump(test_config, f)
config_file_path = f.name

try:
proxy_config = ProxyConfig()
with patch.object(ProxyConfig, "_init_cache") as mock_init:
await proxy_config.load_config(
router=MagicMock(), config_file_path=config_file_path
)

mock_init.assert_called_once()
actual_cache_params = mock_init.call_args.kwargs["cache_params"]

assert actual_cache_params.get("host") == "explicit-redis.internal"
assert actual_cache_params.get("port") == 1234
assert actual_cache_params.get("mode") == "default_off"
finally:
os.unlink(config_file_path)

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.

P2 Missing url connection-key coverage

The fix gates the env-var fallback on "host" not in cache_params and "url" not in cache_params, but the companion guard test only exercises the host path. A user supplying cache_params: {url: "redis://...", mode: default_off} relies on the url branch to suppress env-var loading, and that path has no test. Consider adding a third test analogous to this one but using url instead of host.

Bojun-Vvibe added a commit to Bojun-Vvibe/oss-contributions that referenced this pull request Apr 27, 2026
- BerriAI/litellm#26577 fix(proxy): skip redundant tiktoken recount (merge-after-nits)
- BerriAI/litellm#26576 fix(proxy): load REDIS_* env vars when cache_params has non-connection keys (merge-as-is)
- QwenLM/qwen-code#3667 fix(cli): refresh static header on model switch (merge-after-nits)
- google-gemini/gemini-cli#26005 Fix infinite dialog loop and add ESC support in /skills link (merge-after-nits)
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