From 37a8638f11431f14a286a6d01e42c5545b3b4846 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sat, 18 Jul 2026 04:08:08 +0000 Subject: [PATCH] fix(responses): guard session-reconstruction limit against non-positive env config --- litellm/constants.py | 8 ++++++-- litellm/litellm_core_utils/env_utils.py | 11 +++++++++++ .../litellm_core_utils/test_env_utils.py | 19 +++++++++++++++++++ tests/test_litellm/test_constants.py | 4 ++-- 4 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 tests/test_litellm/litellm_core_utils/test_env_utils.py diff --git a/litellm/constants.py b/litellm/constants.py index 891d3efa7bd..fbe1d51ecec 100644 --- a/litellm/constants.py +++ b/litellm/constants.py @@ -2,11 +2,15 @@ import os import sys from typing import List, Literal, Optional -from litellm.litellm_core_utils.env_utils import get_env_int, get_env_int_or_none +from litellm.litellm_core_utils.env_utils import ( + get_env_int, + get_env_int_or_none, + get_positive_env_int, +) DEFAULT_HEALTH_CHECK_PROMPT = str(os.getenv("DEFAULT_HEALTH_CHECK_PROMPT", "test from litellm")) AZURE_DEFAULT_RESPONSES_API_VERSION = str(os.getenv("AZURE_DEFAULT_RESPONSES_API_VERSION", "preview")) -MAX_SPEND_LOGS_PER_RESPONSES_SESSION = get_env_int("MAX_SPEND_LOGS_PER_RESPONSES_SESSION", 1000) +MAX_SPEND_LOGS_PER_RESPONSES_SESSION = get_positive_env_int("MAX_SPEND_LOGS_PER_RESPONSES_SESSION", 1000) ROUTER_MAX_FALLBACKS = int(os.getenv("ROUTER_MAX_FALLBACKS", 5)) DEFAULT_BATCH_SIZE = int(os.getenv("DEFAULT_BATCH_SIZE", 512)) DEFAULT_FLUSH_INTERVAL_SECONDS = int(os.getenv("DEFAULT_FLUSH_INTERVAL_SECONDS", 5)) diff --git a/litellm/litellm_core_utils/env_utils.py b/litellm/litellm_core_utils/env_utils.py index 3a64f44fb25..2f4a12c5974 100644 --- a/litellm/litellm_core_utils/env_utils.py +++ b/litellm/litellm_core_utils/env_utils.py @@ -21,6 +21,17 @@ def get_env_int(env_var: str, default: int) -> int: return default +def get_positive_env_int(env_var: str, default: int) -> int: + """Parse an environment variable as a strictly positive integer. + + Falls back to default when the value is missing, unparseable, or not > 0, + so a misconfiguration (e.g. an empty string or 0) cannot silently turn a + bound into something degenerate like ``LIMIT 0``. + """ + value = get_env_int(env_var, default) + return value if value > 0 else default + + def get_env_int_or_none(env_var: str) -> int | None: """Parse an environment variable as an integer, returning None when it is unset or unusable. diff --git a/tests/test_litellm/litellm_core_utils/test_env_utils.py b/tests/test_litellm/litellm_core_utils/test_env_utils.py new file mode 100644 index 00000000000..096f9362ca2 --- /dev/null +++ b/tests/test_litellm/litellm_core_utils/test_env_utils.py @@ -0,0 +1,19 @@ +import pytest + +from litellm.litellm_core_utils.env_utils import get_positive_env_int + + +class TestGetPositiveEnvInt: + def test_returns_parsed_positive_value(self, monkeypatch): + monkeypatch.setenv("MY_LIMIT", "42") + assert get_positive_env_int("MY_LIMIT", 1000) == 42 + + def test_falls_back_to_default_when_unset(self, monkeypatch): + monkeypatch.delenv("MY_LIMIT", raising=False) + assert get_positive_env_int("MY_LIMIT", 1000) == 1000 + + @pytest.mark.parametrize("bad_value", ["0", "-1", "-999", "", " ", "abc"]) + def test_falls_back_to_default_on_non_positive_or_invalid(self, monkeypatch, bad_value): + """A misconfigured value must not degrade a bound into e.g. LIMIT 0.""" + monkeypatch.setenv("MY_LIMIT", bad_value) + assert get_positive_env_int("MY_LIMIT", 1000) == 1000 diff --git a/tests/test_litellm/test_constants.py b/tests/test_litellm/test_constants.py index b3c13c6e26e..0e7e7f9012d 100644 --- a/tests/test_litellm/test_constants.py +++ b/tests/test_litellm/test_constants.py @@ -56,10 +56,10 @@ def _build_constant_env_var_map() -> dict[str, str]: env_var_name = child.args[0].value break - # get_env_int("ENV_NAME", default) + # get_env_int("ENV_NAME", default) / get_positive_env_int("ENV_NAME", default) if ( isinstance(child.func, ast.Name) - and child.func.id == "get_env_int" + and child.func.id in ("get_env_int", "get_positive_env_int") and len(child.args) >= 1 and isinstance(child.args[0], ast.Constant) and isinstance(child.args[0].value, str)