litellm - ✅(Solved) Fix [Bug]: OpenRouter endpoints broken (not stripping "openrouter/" from model) since v1.82.3 [2 pull requests, 6 comments, 5 participants]

Official PRs (…)
ON THIS PAGE

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
BerriAI/litellm#24234Fetched 2026-04-08 01:09:07
View on GitHub
Comments
6
Participants
5
Timeline
19
Reactions
4
Author
Timeline (top)
commented ×6labeled ×3referenced ×3subscribed ×3

Error Message

openrouter/openai/gpt-5 is not a valid model

Fix Action

Fixed

PR fix notes

PR #24275: fix(openrouter): strip 'openrouter/' prefix in chat transform_request

Description (problem / solution / changelog)

Summary

Fixes #24234

Problem

OpenRouter chat completions are broken when the model is passed with the openrouter/ provider prefix (e.g. openrouter/mistralai/mistral-7b-instruct). The full string — including openrouter/ — was being sent to the OpenRouter API, which does not recognise it and returns an error.

Root cause

get_llm_provider_logic.py returns early at L166 when it detects custom_llm_provider == "openrouter" and model.startswith("openrouter/"), preserving the prefix in the model string. OpenrouterConfig.transform_request() then forwarded this unparsed string directly to the upstream API.

Fix

Strip the openrouter/ prefix at the start of OpenrouterConfig.transform_request() — consistent with the approach already used in OpenrouterConfig for embeddings (litellm/llms/openrouter/embedding/transformation.py, lines 112–113).

# Before (broken)
model = "openrouter/mistralai/mistral-7b-instruct"  # sent as-is

# After (fixed)
model = "mistralai/mistral-7b-instruct"  # prefix stripped

Testing

Manually verified that the transform now produces the correct model string. Unit tests pass.

Changed files

  • litellm/llms/openrouter/chat/transformation.py (modified, +6/-0)

PR #24282: fix: strip 'openrouter/' prefix from model names (#24234)

Description (problem / solution / changelog)

Fixes #24234

Root Cause

An early return in get_llm_provider_logic.py (line 166-167) was preventing the openrouter/ prefix from being stripped:

if custom_llm_provider == "openrouter" and model.startswith("openrouter/"):
    return model, custom_llm_provider, dynamic_api_key, api_base

This was intended for 'native OpenRouter models' like openrouter/free, but no such models exist in the model registry. All 89 OpenRouter models are multi-segment (e.g. openrouter/anthropic/claude-3.5-sonnet).

The early return caused the full openrouter/anthropic/claude-3.5-sonnet to be sent to the API instead of anthropic/claude-3.5-sonnet, resulting in 400 Bad Request.

Fix

Remove the early return. The existing provider-list stripping logic (line 196-198) correctly handles all OpenRouter models.

Test

Added test_openrouter_model_prefix_stripped verifying the prefix is stripped.

  • Sign the Contributor License Agreement (CLA)
  • Keep scope isolated
  • Add testing

Changed files

  • litellm/litellm_core_utils/get_llm_provider_logic.py (modified, +8/-5)
  • tests/local_testing/test_get_llm_provider.py (modified, +16/-0)

Code Example

services:
  litellm:
    image: docker.litellm.ai/berriai/litellm:main-stable
    volumes:
     - ./config.yaml:/app/config.yaml
    command:
     - "--config=/app/config.yaml"
    ports:
      - "4000:4000" # Map the container port to the host, change the host port if necessary
    env_file:
      - .env # Load local .env file
    environment:
      - DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}
      - STORE_MODEL_IN_DB=True
    depends_on:
      - db  # Indicates that this service depends on the 'db' service, ensuring 'db' starts first
    healthcheck:  # Defines the health check configuration for the container
      test:
        - CMD-SHELL
        - python3 -c "import urllib.request; urllib.request.urlopen('http://localhost:4000/health/liveliness')"  # Command to execute for health check
      interval: 30s  # Perform health check every 30 seconds
      timeout: 10s   # Health check command times out after 10 seconds
      retries: 3     # Retry up to 3 times if health check fails
      start_period: 40s  # Wait 40 seconds after container start before beginning health checks

  db:
    image: postgres:16
    restart: always
    container_name: litellm_db
    env_file:
      - .env
    ports:
      - "5432:5432"
    volumes:
      - /docker/litellm/postgres_data:/var/lib/postgresql/data # Persists Postgres data across container restarts
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -d litellm -U llmproxy"]
      interval: 1s
      timeout: 5s
      retries: 10

---

general_settings:
  store_model_in_db: true
  store_prompts_in_spend_logs: true

litellm_settings:
  drop_params: true
  modify_params: true

---

litellm.BadRequestError: OpenrouterException - {"error":{"message":"openrouter/openai/gpt-5 is not a valid model ID","code":400},"user_id":"user_39l95tavYnvwx08khqJYH3EDhGX"}
stack trace: Traceback (most recent call last):
  File "/usr/lib/python3.13/site-packages/litellm/llms/custom_httpx/llm_http_handler.py", line 175, in _make_common_async_call
    response = await async_httpx_client.post(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<10 lines>...
    )
    ^
  File "/usr/lib/python3.13/site-packages/litellm/litellm_core_utils/logging_utils.py", line 297, in async_wrapper
    result = await func(*args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/litellm/llms/custom_httpx/http_handler.py", line 513, in post
    raise e
  File "/usr/lib/python3.13/site-packages/litellm/llms/custom_httpx/http_handler.py", line 469, in post
    response.raise_for_status()
    ~~~~~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/site-packages/httpx/_models.py", line 829, in raise_for_status
    raise HTTPStatusError(message, request=request, response=self)
httpx.HTTPStatusError: Client error '400 Bad Request' for url 'https://ope

---

litellm.BadRequestError: OpenrouterException - {"error":{"message":"openrouter/openai/gpt-5 is not a valid model ID","code":400},"user_id":"user_39l95tavYnvwx08khqJYH3EDhGX"}
stack trace: Traceback (most recent call last):
  File "/usr/lib/python3.13/site-packages/litellm/llms/custom_httpx/llm_http_handler.py", line 175, in _make_common_async_call
    response = await async_httpx_client.post(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<10 lines>...
    )
    ^
  File "/usr/lib/python3.13/site-packages/litellm/litellm_core_utils/logging_utils.py", line 297, in async_wrapper
    result = await func(*args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/litellm/llms/custom_httpx/http_handler.py", line 513, in post
    raise e
  File "/usr/lib/python3.13/site-packages/litellm/llms/custom_httpx/http_handler.py", line 469, in post
    response.raise_for_status()
    ~~~~~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/site-packages/httpx/_models.py", line 829, in raise_for_status
    raise HTTPStatusError(message, request=request, response=self)
httpx.HTTPStatusError: Client error '400 Bad Request' for url 'https://ope
RAW_BUFFERClick to expand / collapse

Check for existing issues

  • I have searched the existing issues and checked that my issue is not a duplicate.

Error Message

openrouter/openai/gpt-5 is not a valid model

What happened?

I have just updated my docker container with the docker.litellm.ai/berriai/litellm:main-stable tag and now none of my OpenRouter endpoints are working. It might be related to #20516 or #22320 since it looks like the openrouter/ is not stripped in the beginning

Note: the working models are all local or non-openrouter models. All OpenRouter models are failing

<img width="1539" height="700" alt="Image" src="https://github.com/user-attachments/assets/35baa600-e255-41d4-ad01-a873b97ad54f" /> <img width="723" height="562" alt="Image" src="https://github.com/user-attachments/assets/87ab654b-2271-4c2f-8731-ffaf0b992127" />

Steps to Reproduce

  1. Get docker container running (currently with v1.82.3)
services:
  litellm:
    image: docker.litellm.ai/berriai/litellm:main-stable
    volumes:
     - ./config.yaml:/app/config.yaml
    command:
     - "--config=/app/config.yaml"
    ports:
      - "4000:4000" # Map the container port to the host, change the host port if necessary
    env_file:
      - .env # Load local .env file
    environment:
      - DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}
      - STORE_MODEL_IN_DB=True
    depends_on:
      - db  # Indicates that this service depends on the 'db' service, ensuring 'db' starts first
    healthcheck:  # Defines the health check configuration for the container
      test:
        - CMD-SHELL
        - python3 -c "import urllib.request; urllib.request.urlopen('http://localhost:4000/health/liveliness')"  # Command to execute for health check
      interval: 30s  # Perform health check every 30 seconds
      timeout: 10s   # Health check command times out after 10 seconds
      retries: 3     # Retry up to 3 times if health check fails
      start_period: 40s  # Wait 40 seconds after container start before beginning health checks

  db:
    image: postgres:16
    restart: always
    container_name: litellm_db
    env_file:
      - .env
    ports:
      - "5432:5432"
    volumes:
      - /docker/litellm/postgres_data:/var/lib/postgresql/data # Persists Postgres data across container restarts
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -d litellm -U llmproxy"]
      interval: 1s
      timeout: 5s
      retries: 10

config.yaml:

general_settings:
  store_model_in_db: true
  store_prompts_in_spend_logs: true

litellm_settings:
  drop_params: true
  modify_params: true
  1. Add an OpenRouter model via the UI (stored in the database)
  2. It will fail with an error like:
litellm.BadRequestError: OpenrouterException - {"error":{"message":"openrouter/openai/gpt-5 is not a valid model ID","code":400},"user_id":"user_39l95tavYnvwx08khqJYH3EDhGX"}
stack trace: Traceback (most recent call last):
  File "/usr/lib/python3.13/site-packages/litellm/llms/custom_httpx/llm_http_handler.py", line 175, in _make_common_async_call
    response = await async_httpx_client.post(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<10 lines>...
    )
    ^
  File "/usr/lib/python3.13/site-packages/litellm/litellm_core_utils/logging_utils.py", line 297, in async_wrapper
    result = await func(*args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/litellm/llms/custom_httpx/http_handler.py", line 513, in post
    raise e
  File "/usr/lib/python3.13/site-packages/litellm/llms/custom_httpx/http_handler.py", line 469, in post
    response.raise_for_status()
    ~~~~~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/site-packages/httpx/_models.py", line 829, in raise_for_status
    raise HTTPStatusError(message, request=request, response=self)
httpx.HTTPStatusError: Client error '400 Bad Request' for url 'https://ope

Relevant log output

litellm.BadRequestError: OpenrouterException - {"error":{"message":"openrouter/openai/gpt-5 is not a valid model ID","code":400},"user_id":"user_39l95tavYnvwx08khqJYH3EDhGX"}
stack trace: Traceback (most recent call last):
  File "/usr/lib/python3.13/site-packages/litellm/llms/custom_httpx/llm_http_handler.py", line 175, in _make_common_async_call
    response = await async_httpx_client.post(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<10 lines>...
    )
    ^
  File "/usr/lib/python3.13/site-packages/litellm/litellm_core_utils/logging_utils.py", line 297, in async_wrapper
    result = await func(*args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/litellm/llms/custom_httpx/http_handler.py", line 513, in post
    raise e
  File "/usr/lib/python3.13/site-packages/litellm/llms/custom_httpx/http_handler.py", line 469, in post
    response.raise_for_status()
    ~~~~~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/site-packages/httpx/_models.py", line 829, in raise_for_status
    raise HTTPStatusError(message, request=request, response=self)
httpx.HTTPStatusError: Client error '400 Bad Request' for url 'https://ope

What part of LiteLLM is this about?

Proxy

What LiteLLM version are you on ?

v1.82.3

Twitter / LinkedIn details

No response

extent analysis

Fix Plan

The issue seems to be related to the openrouter/ prefix not being stripped from the model ID. To fix this, we need to modify the code to remove the prefix before making the API call.

Step-by-Step Solution

  1. Locate the relevant code: Find the file llm_http_handler.py and navigate to the _make_common_async_call function.
  2. Modify the model ID: Before making the API call, remove the openrouter/ prefix from the model ID using the str.replace() method.
model_id = model_id.replace("openrouter/", "")
  1. Update the API call: Use the modified model ID in the API call.
response = await async_httpx_client.post(
    f"https://api.openrouter.com/v1/models/{model_id}/...",
    ...
)

Example Code

# llm_http_handler.py

async def _make_common_async_call(self, model_id, ...):
    # Remove the openrouter/ prefix from the model ID
    model_id = model_id.replace("openrouter/", "")
    
    # Make the API call with the modified model ID
    response = await async_httpx_client.post(
        f"https://api.openrouter.com/v1/models/{model_id}/...",
        ...
    )
    ...

Verification

To verify that the fix worked, try adding an OpenRouter model via the UI and check if the API call is successful. You can also check the logs to see if the openrouter/ prefix is being removed correctly.

Extra Tips

  • Make sure to test the fix thoroughly to ensure that it doesn't introduce any new issues.
  • Consider adding a check to handle cases where the openrouter/ prefix is not present in the model ID.
  • If you're using a version control system, make sure to commit the changes and update the relevant documentation.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING