From 79960073b1ea7c18a34d6163aed72e71be037e18 Mon Sep 17 00:00:00 2001 From: mateo-berri <277851410+mateo-berri@users.noreply.github.com> Date: Sat, 19 Sep 2026 12:20:26 -0700 Subject: [PATCH 1/5] fix(bedrock): clamp maxTokens to the 16-token minimum for OpenAI GPT and xAI Grok models on Converse (#41870) Backport of #41870 to stable/1.98.x. Cherry-picked from a6e3a72ed8 (main) with -m 1. converse_transformation.py conflicted because this line has no `import re` and no _is_openai_gpt_reasoning_model helper next to the insertion point. The resolution adds exactly the four hunks #41870 merged: the import, the 16-token constant, _requires_min_max_tokens, and the clamped maxTokens assignment. The test file applied clean. --- .../bedrock/chat/converse_transformation.py | 12 +++++++- .../chat/test_converse_transformation.py | 28 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/litellm/llms/bedrock/chat/converse_transformation.py b/litellm/llms/bedrock/chat/converse_transformation.py index 85918d40e12..a89255a46a5 100644 --- a/litellm/llms/bedrock/chat/converse_transformation.py +++ b/litellm/llms/bedrock/chat/converse_transformation.py @@ -4,6 +4,7 @@ Translating between OpenAI's `/chat/completion` format and Amazon's `/converse` import copy import json +import re import time import types from typing import Final, Literal, cast, overload @@ -92,6 +93,7 @@ BEDROCK_COMPUTER_USE_TOOLS: Final = [ "bash_", "text_editor_", ] +BEDROCK_OPENAI_COMPAT_MIN_MAX_TOKENS: Final = 16 # Beta header patterns that are not supported by Bedrock Converse API # These will be filtered out to prevent errors @@ -280,6 +282,10 @@ class AmazonConverseConfig(BaseConfig): llm_provider="bedrock", ) + @staticmethod + def _requires_min_max_tokens(model: str) -> bool: + return re.search(r"openai\.gpt-\d|xai\.grok-", model) is not None + def _is_nova_2_model(self, model: str) -> bool: """ Check if the model is a Nova 2 model that supports reasoningConfig. @@ -858,7 +864,11 @@ class AmazonConverseConfig(BaseConfig): is_thinking_enabled=is_thinking_enabled, ) if param == "max_tokens" or param == "max_completion_tokens": - optional_params["maxTokens"] = value + optional_params["maxTokens"] = ( + max(value, BEDROCK_OPENAI_COMPAT_MIN_MAX_TOKENS) + if isinstance(value, int) and self._requires_min_max_tokens(model) + else value + ) if param == "stream": optional_params["stream"] = value if param == "stop": diff --git a/tests/test_litellm/llms/bedrock/chat/test_converse_transformation.py b/tests/test_litellm/llms/bedrock/chat/test_converse_transformation.py index d1d1f9ab489..d94c908b5f0 100644 --- a/tests/test_litellm/llms/bedrock/chat/test_converse_transformation.py +++ b/tests/test_litellm/llms/bedrock/chat/test_converse_transformation.py @@ -288,6 +288,34 @@ def test_reasoning_with_forced_tool_choice_switches_to_auto(): assert optional_params["tool_choice"] == {"auto": {}} +@pytest.mark.parametrize( + "model, param, value, expected_max_tokens", + [ + ("us.openai.gpt-6-astra", "max_tokens", 1, 16), + ("us.openai.gpt-6-astra", "max_completion_tokens", 1, 16), + ("us.openai.gpt-6-astra", "max_tokens", 64, 64), + ("us.xai.grok-4.6", "max_tokens", 1, 16), + ("global.xai.grok-4.6", "max_completion_tokens", 1, 16), + ("us.xai.grok-4.6", "max_tokens", 32, 32), + ("anthropic.claude-sonnet-4-5-20250929-v1:0", "max_tokens", 1, 1), + ("arn:aws:bedrock:us-east-1:123456789012:inference-profile/us.openai.gpt-6-astra", "max_tokens", 1, 16), + ("arn:aws:bedrock:us-east-1:123456789012:inference-profile/global.xai.grok-4.6", "max_tokens", 1, 16), + ("arn:aws:bedrock:us-east-1:123456789012:application-inference-profile/abc123xyz", "max_tokens", 1, 1), + ], +) +def test_map_openai_params_enforces_minimum_max_tokens_for_openai_compat_models( + model: str, param: str, value: int, expected_max_tokens: int +): + optional_params = AmazonConverseConfig().map_openai_params( + non_default_params={param: value}, + optional_params={}, + model=model, + drop_params=False, + ) + + assert optional_params["maxTokens"] == expected_max_tokens + + @pytest.mark.parametrize( "model", [ From c32db1b5121c2f4666703ce71a0a7b7b1af3b078 Mon Sep 17 00:00:00 2001 From: mateo-berri <277851410+mateo-berri@users.noreply.github.com> Date: Sat, 19 Sep 2026 12:20:58 -0700 Subject: [PATCH 2/5] bump: version 1.98.1 --- pyproject.toml | 4 ++-- uv.lock | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 275343ccef6..68f9fbc8328 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "litellm" -version = "1.98.0" +version = "1.98.1" description = "Library to easily interface with LLM API providers" readme = "README.md" requires-python = ">=3.10, <3.15" @@ -306,7 +306,7 @@ members = ["enterprise", "litellm-proxy-extras"] profile = "black" [tool.commitizen] -version = "1.98.0" +version = "1.98.1" version_files = [ "pyproject.toml:^version", ] diff --git a/uv.lock b/uv.lock index 1cc924e50fe..79561af2ed9 100644 --- a/uv.lock +++ b/uv.lock @@ -4194,7 +4194,7 @@ wheels = [ [[package]] name = "litellm" -version = "1.98.0" +version = "1.98.1" source = { editable = "." } dependencies = [ { name = "aiohttp" }, From 9f48ccaecf3e1c02c14408fe1aab94d051a8bc1a Mon Sep 17 00:00:00 2001 From: mateo-berri <277851410+mateo-berri@users.noreply.github.com> Date: Sat, 19 Sep 2026 12:55:31 -0700 Subject: [PATCH 3/5] fix(bedrock): match any openai.gpt- model in the Converse reasoning gate Backports the Converse part of fbc6fb56ae from main (PR #31884) together with the OpenAI GPT reasoning gate this line never had (PR #38279: 74e86d3c0d, 9cc276a96e, 418012aac5): reasoning_effort maps to reasoning.effort for openai.gpt- models and Anthropic's thinking block is skipped for them. Without it a GPT-6 model fell through to Anthropic's thinking block and Bedrock rejected the first real turn after a Claude Code /model switch with 400 Unknown parameter: 'thinking'. #38279's cost-map JSON and cross-region test changes, the Nova 2 tool_choice registry keys, and the invoke json_mode forwarding stay on main --- .../bedrock/chat/converse_transformation.py | 16 ++++- litellm/types/llms/bedrock.py | 6 +- .../chat/test_converse_transformation.py | 68 +++++++++++++++++++ 3 files changed, 87 insertions(+), 3 deletions(-) diff --git a/litellm/llms/bedrock/chat/converse_transformation.py b/litellm/llms/bedrock/chat/converse_transformation.py index a89255a46a5..0d99bb957e0 100644 --- a/litellm/llms/bedrock/chat/converse_transformation.py +++ b/litellm/llms/bedrock/chat/converse_transformation.py @@ -286,6 +286,10 @@ class AmazonConverseConfig(BaseConfig): def _requires_min_max_tokens(model: str) -> bool: return re.search(r"openai\.gpt-\d|xai\.grok-", model) is not None + @staticmethod + def _is_openai_gpt_reasoning_model(model: str) -> bool: + return re.search(r"openai\.gpt-\d", model) is not None + def _is_nova_2_model(self, model: str) -> bool: """ Check if the model is a Nova 2 model that supports reasoningConfig. @@ -416,12 +420,16 @@ class AmazonConverseConfig(BaseConfig): Handle the reasoning_effort parameter based on the model type. - GPT-OSS models: passed through unchanged via additionalModelRequestFields. + - OpenAI GPT-5.x and GPT-6 models: mapped to ``reasoning.effort`` via additionalModelRequestFields. - Nova 2 models: transformed to reasoningConfig. - Anthropic models: mapped to ``thinking`` (and ``output_config.effort`` on adaptive Claude 4.6 / 4.7). """ if "gpt-oss" in model: optional_params["reasoning_effort"] = reasoning_effort + elif self._is_openai_gpt_reasoning_model(model): + reasoning: Final[BedrockConverseGptReasoningEffortBlock] = {"effort": reasoning_effort} + optional_params["reasoning"] = reasoning # rebind-ok: out-param store like siblings elif self._is_nova_2_model(model): reasoning_config: Final = self._transform_reasoning_effort_to_reasoning_config(reasoning_effort) optional_params.update(reasoning_config) @@ -553,7 +561,11 @@ class AmazonConverseConfig(BaseConfig): # only anthropic and mistral support tool choice config. otherwise (E.g. cohere) will fail the call - https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_ToolChoice.html supported_params.append("tool_choice") - if "gpt-oss" in model: + if ( + "gpt-oss" in model + or self._is_openai_gpt_reasoning_model(model) + or self._is_openai_gpt_reasoning_model(base_model) + ): supported_params.append("reasoning_effort") elif self._is_nova_2_model(model): # Nova 2 models support reasoning_effort (transformed to reasoningConfig) @@ -905,7 +917,7 @@ class AmazonConverseConfig(BaseConfig): optional_params["_parallel_tool_use_config"] = { "tool_choice": {"type": "auto", "disable_parallel_tool_use": not value} } - if param == "thinking": + if param == "thinking" and not self._is_openai_gpt_reasoning_model(model): if ( isinstance(value, dict) and value.get("type") == "adaptive" diff --git a/litellm/types/llms/bedrock.py b/litellm/types/llms/bedrock.py index 5665aa3277a..97d068f898d 100644 --- a/litellm/types/llms/bedrock.py +++ b/litellm/types/llms/bedrock.py @@ -2,7 +2,7 @@ import json from enum import Enum from typing import TYPE_CHECKING, Any, Final, Literal -from typing_extensions import Required, TypedDict, override +from typing_extensions import ReadOnly, Required, TypedDict, override from .openai import ChatCompletionToolCallChunk @@ -96,6 +96,10 @@ class BedrockConverseReasoningContentBlockDelta(TypedDict, total=False): text: str +class BedrockConverseGptReasoningEffortBlock(TypedDict): + effort: ReadOnly[str] + + class GuardrailConverseTextBlock(TypedDict, total=False): text: str diff --git a/tests/test_litellm/llms/bedrock/chat/test_converse_transformation.py b/tests/test_litellm/llms/bedrock/chat/test_converse_transformation.py index d94c908b5f0..7d23b371620 100644 --- a/tests/test_litellm/llms/bedrock/chat/test_converse_transformation.py +++ b/tests/test_litellm/llms/bedrock/chat/test_converse_transformation.py @@ -288,6 +288,74 @@ def test_reasoning_with_forced_tool_choice_switches_to_auto(): assert optional_params["tool_choice"] == {"auto": {}} +@pytest.mark.parametrize( + "model", + [ + "us.openai.gpt-5.6-sol", + "global.openai.gpt-5.6-terra", + "bedrock/converse/us.openai.gpt-5.6-luna", + "us.openai.gpt-6-astra", + "bedrock/converse/global.openai.gpt-6-astra", + ], +) +def test_reasoning_effort_maps_to_reasoning_effort_for_openai_gpt5_converse(model): + """OpenAI GPT-5.x on Bedrock Converse routes reasoning_effort to + ``additionalModelRequestFields.reasoning.effort`` rather than Anthropic ``thinking``.""" + config = AmazonConverseConfig() + + assert "reasoning_effort" in config.get_supported_openai_params(model=model) + + optional_params = config.map_openai_params( + non_default_params={"reasoning_effort": "high"}, + optional_params={}, + model=model, + drop_params=False, + ) + + assert optional_params["reasoning"] == {"effort": "high"} + assert "thinking" not in optional_params + assert "reasoning_effort" not in optional_params + + _, additional_request_params, _, _ = config._prepare_request_params(optional_params, model) + assert additional_request_params["reasoning"] == {"effort": "high"} + assert "thinking" not in additional_request_params + + +@pytest.mark.parametrize( + "model", + [ + "us.openai.gpt-5.6-sol", + "bedrock/converse/global.openai.gpt-5.6-luna", + "us.openai.gpt-6-astra", + ], +) +def test_openai_gpt5_converse_never_forwards_thinking(model): + """GPT-5.x on Converse must never send Anthropic ``thinking``/``output_config`` (Bedrock rejects them). + + Regression: ``thinking`` is not advertised as supported, and even when supplied alongside + ``reasoning_effort`` in either order it never survives into the request.""" + config = AmazonConverseConfig() + + supported = config.get_supported_openai_params(model=model) + assert "thinking" not in supported + assert "output_config" not in supported + + thinking_block = {"type": "enabled", "budget_tokens": 2048} + for non_default_params in ( + {"reasoning_effort": "high", "thinking": thinking_block}, + {"thinking": thinking_block, "reasoning_effort": "high"}, + ): + optional_params = config.map_openai_params( + non_default_params=dict(non_default_params), + optional_params={}, + model=model, + drop_params=False, + ) + _, additional_request_params, _, _ = config._prepare_request_params(optional_params, model) + assert additional_request_params["reasoning"] == {"effort": "high"} + assert "thinking" not in additional_request_params + + @pytest.mark.parametrize( "model, param, value, expected_max_tokens", [ From 1af2cad04ab4d260d9cc2444ff8c3ff67c454c66 Mon Sep 17 00:00:00 2001 From: mateo-berri <277851410+mateo-berri@users.noreply.github.com> Date: Sun, 30 Aug 2026 13:11:32 -0700 Subject: [PATCH 4/5] fix(docker): bump wolfi-base for glibc 2.44 and pin apk python to 3.13 (cherry picked from commit 14f392bb9b10bdcee7e134e8132f1b070e913e0a) (cherry picked from commit 728dec258fb8de6c799ba9a40a1a1949699eafc0) --- Dockerfile | 15 ++++++++------- backend/Dockerfile | 12 ++++++------ docker/Dockerfile.database | 15 ++++++++------- docker/Dockerfile.non_root | 17 +++++++++-------- gateway/Dockerfile | 12 ++++++------ 5 files changed, 37 insertions(+), 34 deletions(-) diff --git a/Dockerfile b/Dockerfile index 66ce3af4a65..b3ee85e9ed1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,10 @@ # syntax=docker/dockerfile:1.7 # Base image for building -ARG LITELLM_BUILD_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:42df77a9974d6ec8b17a5ee8bc23b532600a44d705acef2409e0933c1251b45f +ARG LITELLM_BUILD_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:e624c5d5e42382ce7165ddafcbbf8e6769a24cbd02ea6114b880b05ae5ba2a8d # Runtime image -ARG LITELLM_RUNTIME_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:42df77a9974d6ec8b17a5ee8bc23b532600a44d705acef2409e0933c1251b45f +ARG LITELLM_RUNTIME_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:e624c5d5e42382ce7165ddafcbbf8e6769a24cbd02ea6114b880b05ae5ba2a8d ARG UV_IMAGE=ghcr.io/astral-sh/uv:0.11.7@sha256:240fb85ab0f263ef12f492d8476aa3a2e4e1e333f7d67fbdd923d00a506a516a # Pinned by digest like the other base images; bump explicitly on Node upgrades. ARG UI_BUILD_IMAGE=node:24.19-alpine3.24@sha256:d32cdf619f63fe0471182d08996dd516c6275bb5fd31ae06e55a570bd9e1ad43 @@ -40,8 +40,8 @@ COPY --from=uvbin /uvx /usr/local/bin/uvx RUN apk add --no-cache \ bash \ gcc \ - python3 \ - python3-dev \ + python-3.13 \ + python-3.13-dev \ rust \ openssl \ openssl-dev \ @@ -51,6 +51,7 @@ RUN apk add --no-cache \ ENV UV_PROJECT_ENVIRONMENT=/app/.venv \ UV_LINK_MODE=copy \ + UV_PYTHON_DOWNLOADS=0 \ PATH="/app/.venv/bin:${PATH}" # Copy dependency metadata first for layer caching @@ -65,7 +66,7 @@ RUN uv sync --frozen --no-install-project --no-install-workspace --no-default-gr --extra extra_proxy \ --extra semantic-router \ --extra saml \ - --python python3 + --python python3.13 # Copy full source tree COPY . . @@ -86,7 +87,7 @@ RUN uv sync --frozen --no-default-groups --no-editable \ --extra extra_proxy \ --extra semantic-router \ --extra saml \ - --python python3 + --python python3.13 RUN HOME=/opt/prisma XDG_CACHE_HOME=/opt/prisma/.cache PRISMA_BINARY_CACHE_DIR=/opt/prisma/binaries \ npm_config_cache=/root/.npm \ @@ -101,7 +102,7 @@ FROM $LITELLM_RUNTIME_IMAGE AS runtime USER root # node (without npm) is required by the prisma CLI at runtime -RUN apk add --no-cache bash openssl tzdata nodejs python3 libsndfile +RUN apk add --no-cache bash openssl tzdata nodejs python-3.13 libsndfile WORKDIR /app ENV PATH="/app/.venv/bin:${PATH}" \ diff --git a/backend/Dockerfile b/backend/Dockerfile index 853c74b05ca..aa01b9fba8b 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,5 +1,5 @@ -ARG LITELLM_BUILD_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:42df77a9974d6ec8b17a5ee8bc23b532600a44d705acef2409e0933c1251b45f -ARG LITELLM_RUNTIME_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:42df77a9974d6ec8b17a5ee8bc23b532600a44d705acef2409e0933c1251b45f +ARG LITELLM_BUILD_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:e624c5d5e42382ce7165ddafcbbf8e6769a24cbd02ea6114b880b05ae5ba2a8d +ARG LITELLM_RUNTIME_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:e624c5d5e42382ce7165ddafcbbf8e6769a24cbd02ea6114b880b05ae5ba2a8d ARG UV_IMAGE=ghcr.io/astral-sh/uv:0.11.7@sha256:240fb85ab0f263ef12f492d8476aa3a2e4e1e333f7d67fbdd923d00a506a516a FROM $UV_IMAGE AS uvbin @@ -16,7 +16,7 @@ COPY --from=uvbin /uv /uvx /usr/local/bin/ # instead of nodeenv downloading one whose dynamic deps may not be in Wolfi # (e.g. Node 26.2.0 needs libatomic). Retry for transient apk.cgr.dev flakes. RUN for i in 1 2 3; do \ - apk add --no-cache bash gcc python3 python3-dev openssl openssl-dev libsndfile nodejs npm && break; \ + apk add --no-cache bash gcc python-3.13 python-3.13-dev openssl openssl-dev libsndfile nodejs npm && break; \ [ $i = 3 ] && { echo "apk add failed after 3 retries" >&2; exit 1; }; \ sleep 5; \ done @@ -46,7 +46,7 @@ RUN --mount=type=cache,target=/root/.cache/uv \ --extra proxy-runtime \ --extra extra_proxy \ --extra semantic-router \ - --python python3 + --python python3.13 # Stage 2 — copy source and install the project + workspace members. COPY . . @@ -57,7 +57,7 @@ RUN --mount=type=cache,target=/root/.cache/uv \ --extra proxy-runtime \ --extra extra_proxy \ --extra semantic-router \ - --python python3 + --python python3.13 RUN HOME=/opt/prisma XDG_CACHE_HOME=/opt/prisma/.cache PRISMA_BINARY_CACHE_DIR=/opt/prisma/binaries \ npm_config_cache=/root/.npm \ @@ -71,7 +71,7 @@ FROM $LITELLM_RUNTIME_IMAGE AS runtime USER root RUN for i in 1 2 3; do \ - apk add --no-cache bash openssl tzdata python3 libsndfile libatomic && break; \ + apk add --no-cache bash openssl tzdata python-3.13 libsndfile libatomic && break; \ [ $i = 3 ] && { echo "apk add failed after 3 retries" >&2; exit 1; }; \ sleep 5; \ done diff --git a/docker/Dockerfile.database b/docker/Dockerfile.database index 4bf3ae2b417..c1348f68231 100644 --- a/docker/Dockerfile.database +++ b/docker/Dockerfile.database @@ -1,10 +1,10 @@ # syntax=docker/dockerfile:1.7 # Base image for building -ARG LITELLM_BUILD_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:42df77a9974d6ec8b17a5ee8bc23b532600a44d705acef2409e0933c1251b45f +ARG LITELLM_BUILD_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:e624c5d5e42382ce7165ddafcbbf8e6769a24cbd02ea6114b880b05ae5ba2a8d # Runtime image -ARG LITELLM_RUNTIME_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:42df77a9974d6ec8b17a5ee8bc23b532600a44d705acef2409e0933c1251b45f +ARG LITELLM_RUNTIME_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:e624c5d5e42382ce7165ddafcbbf8e6769a24cbd02ea6114b880b05ae5ba2a8d ARG UV_IMAGE=ghcr.io/astral-sh/uv:0.11.7@sha256:240fb85ab0f263ef12f492d8476aa3a2e4e1e333f7d67fbdd923d00a506a516a # Pinned by digest like the other base images; bump explicitly on Node upgrades. ARG UI_BUILD_IMAGE=node:24.19-alpine3.24@sha256:d32cdf619f63fe0471182d08996dd516c6275bb5fd31ae06e55a570bd9e1ad43 @@ -39,8 +39,8 @@ COPY --from=uvbin /uvx /usr/local/bin/uvx RUN apk add --no-cache \ bash \ gcc \ - python3 \ - python3-dev \ + python-3.13 \ + python-3.13-dev \ openssl \ openssl-dev \ nodejs \ @@ -49,6 +49,7 @@ RUN apk add --no-cache \ ENV UV_PROJECT_ENVIRONMENT=/app/.venv \ UV_LINK_MODE=copy \ + UV_PYTHON_DOWNLOADS=0 \ PATH="/app/.venv/bin:${PATH}" # Copy dependency metadata first for layer caching @@ -63,7 +64,7 @@ RUN uv sync --frozen --no-install-project --no-install-workspace --no-default-gr --extra extra_proxy \ --extra semantic-router \ --extra saml \ - --python python3 + --python python3.13 # Copy full source tree COPY . . @@ -84,7 +85,7 @@ RUN uv sync --frozen --no-default-groups --no-editable \ --extra extra_proxy \ --extra semantic-router \ --extra saml \ - --python python3 + --python python3.13 RUN HOME=/opt/prisma XDG_CACHE_HOME=/opt/prisma/.cache PRISMA_BINARY_CACHE_DIR=/opt/prisma/binaries \ npm_config_cache=/root/.npm \ @@ -98,7 +99,7 @@ FROM $LITELLM_RUNTIME_IMAGE AS runtime USER root # node (without npm) is required by the prisma CLI at runtime -RUN apk add --no-cache bash openssl tzdata nodejs python3 libsndfile +RUN apk add --no-cache bash openssl tzdata nodejs python-3.13 libsndfile WORKDIR /app ENV PATH="/app/.venv/bin:${PATH}" \ diff --git a/docker/Dockerfile.non_root b/docker/Dockerfile.non_root index 7392cc09a0d..2221435a83a 100644 --- a/docker/Dockerfile.non_root +++ b/docker/Dockerfile.non_root @@ -1,8 +1,8 @@ # syntax=docker/dockerfile:1.7 # Base images -ARG LITELLM_BUILD_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:42df77a9974d6ec8b17a5ee8bc23b532600a44d705acef2409e0933c1251b45f -ARG LITELLM_RUNTIME_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:42df77a9974d6ec8b17a5ee8bc23b532600a44d705acef2409e0933c1251b45f +ARG LITELLM_BUILD_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:e624c5d5e42382ce7165ddafcbbf8e6769a24cbd02ea6114b880b05ae5ba2a8d +ARG LITELLM_RUNTIME_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:e624c5d5e42382ce7165ddafcbbf8e6769a24cbd02ea6114b880b05ae5ba2a8d ARG PROXY_EXTRAS_SOURCE=published ARG UV_IMAGE=ghcr.io/astral-sh/uv:0.11.7@sha256:240fb85ab0f263ef12f492d8476aa3a2e4e1e333f7d67fbdd923d00a506a516a # Pinned by digest like the other base images; bump explicitly on Node upgrades. @@ -37,8 +37,8 @@ COPY --from=uvbin /uvx /usr/local/bin/uvx RUN for i in 1 2 3; do \ apk add --no-cache \ - python3 \ - python3-dev \ + python-3.13 \ + python-3.13-dev \ gcc \ rust \ bash \ @@ -52,6 +52,7 @@ RUN for i in 1 2 3; do \ ENV UV_PROJECT_ENVIRONMENT=/app/.venv \ UV_LINK_MODE=copy \ + UV_PYTHON_DOWNLOADS=0 \ PATH="/app/.venv/bin:${PATH}" \ LITELLM_NON_ROOT=true \ XDG_CACHE_HOME=/app/.cache @@ -69,7 +70,7 @@ RUN --mount=type=cache,target=/app/.cache/uv,id=litellm-uv-cache \ --extra extra_proxy \ --extra semantic-router \ --extra saml \ - --python python3 + --python python3.13 # Copy full source tree COPY . . @@ -96,7 +97,7 @@ RUN --mount=type=cache,target=/app/.cache/uv,id=litellm-uv-cache \ --extra extra_proxy \ --extra semantic-router \ --extra saml \ - --python python3 \ + --python python3.13 \ --no-sources-package litellm-proxy-extras; \ else \ uv sync --frozen --no-default-groups --no-editable \ @@ -105,7 +106,7 @@ RUN --mount=type=cache,target=/app/.cache/uv,id=litellm-uv-cache \ --extra extra_proxy \ --extra semantic-router \ --extra saml \ - --python python3; \ + --python python3.13; \ fi RUN HOME=/opt/prisma XDG_CACHE_HOME=/opt/prisma/.cache PRISMA_BINARY_CACHE_DIR=/opt/prisma/binaries \ @@ -124,7 +125,7 @@ RUN for i in 1 2 3; do \ apk upgrade --no-cache && break || sleep 5; \ done && \ for i in 1 2 3; do \ - apk add --no-cache python3 bash openssl tzdata libsndfile nodejs && break || sleep 5; \ + apk add --no-cache python-3.13 bash openssl tzdata libsndfile nodejs && break || sleep 5; \ done # Copy only what runtime needs. The application is installed inside the venv; diff --git a/gateway/Dockerfile b/gateway/Dockerfile index 223df524d7c..308d70a6b26 100644 --- a/gateway/Dockerfile +++ b/gateway/Dockerfile @@ -1,5 +1,5 @@ -ARG LITELLM_BUILD_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:42df77a9974d6ec8b17a5ee8bc23b532600a44d705acef2409e0933c1251b45f -ARG LITELLM_RUNTIME_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:42df77a9974d6ec8b17a5ee8bc23b532600a44d705acef2409e0933c1251b45f +ARG LITELLM_BUILD_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:e624c5d5e42382ce7165ddafcbbf8e6769a24cbd02ea6114b880b05ae5ba2a8d +ARG LITELLM_RUNTIME_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:e624c5d5e42382ce7165ddafcbbf8e6769a24cbd02ea6114b880b05ae5ba2a8d ARG UV_IMAGE=ghcr.io/astral-sh/uv:0.11.7@sha256:240fb85ab0f263ef12f492d8476aa3a2e4e1e333f7d67fbdd923d00a506a516a FROM $UV_IMAGE AS uvbin @@ -16,7 +16,7 @@ COPY --from=uvbin /uv /uvx /usr/local/bin/ # instead of nodeenv downloading one whose dynamic deps may not be in Wolfi # (e.g. Node 26.2.0 needs libatomic). Retry for transient apk.cgr.dev flakes. RUN for i in 1 2 3; do \ - apk add --no-cache bash gcc python3 python3-dev openssl openssl-dev libsndfile nodejs npm && break; \ + apk add --no-cache bash gcc python-3.13 python-3.13-dev openssl openssl-dev libsndfile nodejs npm && break; \ [ $i = 3 ] && { echo "apk add failed after 3 retries" >&2; exit 1; }; \ sleep 5; \ done @@ -47,7 +47,7 @@ RUN --mount=type=cache,target=/root/.cache/uv \ --extra extra_proxy \ --extra semantic-router \ --extra bedrock-realtime \ - --python python3 + --python python3.13 # Stage 2 — copy source and install the project + workspace members. COPY . . @@ -59,7 +59,7 @@ RUN --mount=type=cache,target=/root/.cache/uv \ --extra extra_proxy \ --extra semantic-router \ --extra bedrock-realtime \ - --python python3 + --python python3.13 RUN HOME=/opt/prisma XDG_CACHE_HOME=/opt/prisma/.cache PRISMA_BINARY_CACHE_DIR=/opt/prisma/binaries \ npm_config_cache=/root/.npm \ @@ -73,7 +73,7 @@ FROM $LITELLM_RUNTIME_IMAGE AS runtime USER root RUN for i in 1 2 3; do \ - apk add --no-cache bash openssl tzdata python3 libsndfile libatomic && break; \ + apk add --no-cache bash openssl tzdata python-3.13 libsndfile libatomic && break; \ [ $i = 3 ] && { echo "apk add failed after 3 retries" >&2; exit 1; }; \ sleep 5; \ done From 0c0dda97809e5096f58344be77eeac8ced1f86e6 Mon Sep 17 00:00:00 2001 From: mateo-berri <277851410+mateo-berri@users.noreply.github.com> Date: Mon, 31 Aug 2026 09:53:01 -0700 Subject: [PATCH 5/5] fix(docker): bump wolfi-base for glibc 2.44 and pin apk python to 3.13 in migrations image (cherry picked from commit 39473745ddb6759b14397df3e9f9499e7b49ce0b) --- migrations/Dockerfile | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/migrations/Dockerfile b/migrations/Dockerfile index 52795d426ec..c6d1b0cc46e 100644 --- a/migrations/Dockerfile +++ b/migrations/Dockerfile @@ -1,5 +1,5 @@ -ARG LITELLM_BUILD_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:42df77a9974d6ec8b17a5ee8bc23b532600a44d705acef2409e0933c1251b45f -ARG LITELLM_RUNTIME_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:42df77a9974d6ec8b17a5ee8bc23b532600a44d705acef2409e0933c1251b45f +ARG LITELLM_BUILD_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:e624c5d5e42382ce7165ddafcbbf8e6769a24cbd02ea6114b880b05ae5ba2a8d +ARG LITELLM_RUNTIME_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:e624c5d5e42382ce7165ddafcbbf8e6769a24cbd02ea6114b880b05ae5ba2a8d ARG UV_IMAGE=ghcr.io/astral-sh/uv:0.11.7@sha256:240fb85ab0f263ef12f492d8476aa3a2e4e1e333f7d67fbdd923d00a506a516a FROM $UV_IMAGE AS uvbin @@ -35,7 +35,7 @@ COPY --from=uvbin /uv /uvx /usr/local/bin/ # instead of nodeenv downloading one whose dynamic deps may not be in Wolfi # (e.g. Node 26.2.0 needs libatomic). Retry for transient apk.cgr.dev flakes. RUN for i in 1 2 3; do \ - apk add --no-cache bash gcc python3 python3-dev openssl openssl-dev libsndfile nodejs npm && break; \ + apk add --no-cache bash gcc python-3.13 python-3.13-dev openssl openssl-dev libsndfile nodejs npm && break; \ [ $i = 3 ] && { echo "apk add failed after 3 retries" >&2; exit 1; }; \ sleep 5; \ done @@ -56,7 +56,7 @@ RUN --mount=type=cache,target=/root/.cache/uv \ uv sync --frozen --no-install-project --no-install-workspace --no-default-groups --no-editable \ --extra proxy \ --extra extra_proxy \ - --python python3 + --python python3.13 # Stage 2 — copy source and install the project + workspace members. COPY . . @@ -65,7 +65,7 @@ RUN --mount=type=cache,target=/root/.cache/uv \ uv sync --frozen --no-default-groups --no-editable \ --extra proxy \ --extra extra_proxy \ - --python python3 + --python python3.13 COPY migrations/run.py /app/run.py @@ -87,7 +87,7 @@ FROM $LITELLM_RUNTIME_IMAGE AS runtime USER root RUN for i in 1 2 3; do \ - apk add --no-cache bash openssl tzdata python3 nodejs libsndfile libatomic && break; \ + apk add --no-cache bash openssl tzdata python-3.13 nodejs libsndfile libatomic && break; \ [ $i = 3 ] && { echo "apk add failed after 3 retries" >&2; exit 1; }; \ sleep 5; \ done