litellm - ✅(Solved) Fix Responses API → Chat Completions bridge does not translate `developer` role to `system` for non-OpenAI providers [2 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

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#24664Fetched 2026-04-08 01:37:20
View on GitHub
Comments
0
Participants
1
Timeline
5
Reactions
2
Participants
Timeline (top)
labeled ×3cross-referenced ×2

Error Message

litellm.BadRequestError: OpenAIException - {"error":{"message":"Unexpected message role.","type":"BadRequestError","param":null,"code":400}}. Received Model Group=vllm-default Available Model Group Fallbacks=['openai/gpt-5.2'] Error doing the fallback: litellm.BadRequestError: OpenAIException - {"detail":"Unsupported parameter: metadata"}No fallback model group found for original model_group=openai/gpt-5.2. Fallbacks=[{'vllm-default': ['openai/gpt-5.2']}]. Received Model Group=openai/gpt-5.2 Available Model Group Fallbacks=None Error doing the fallback: litellm.BadRequestError: OpenAIException - {"detail":"Unsupported parameter: metadata"}No fallback model group found for original model_group=openai/gpt-5.2. Fallbacks=[{'vllm-default': ['openai/gpt-5.2']}]

Root Cause

The fallback path also fails because the metadata parameter from the Responses API request is forwarded to the Chat Completions call, which downstream providers may not support.

PR fix notes

PR #24670: fix(responses): translate developer role to system in Responses→Chat bridge

Description (problem / solution / changelog)

Summary

Fixes #24664

When a Responses API request (/v1/responses) contains messages with role: "developer" (the standard Responses API equivalent of system), the bridge now correctly normalises it to "system" before forwarding to Chat Completions.

Previously, providers like vLLM would reject the request with "Unexpected message role: developer" because they only recognise system, user, assistant, and tool.

Additionally, the metadata field from the Responses API request is no longer forwarded as a top-level param to downstream Chat Completions calls — this prevents UnexpectedKwarg errors on strict providers.

Changes

  • litellm/responses/litellm_completion_transformation/transformation.py:
    • _transform_responses_api_input_item_to_chat_completion_message: map role=developerrole=system
    • transform_responses_api_request_to_completion: remove metadata from Chat Completions forwarding

Testing

Manual repro before fix:

import litellm
resp = litellm.responses(
    model="hosted_vllm/meta-llama/Llama-3.1-8B",
    input=[{"role": "developer", "content": "You are a helpful assistant."},
           {"role": "user", "content": "Hello"}],
    api_base="http://localhost:8000"
)
# Before: raises BadRequestError: Unexpected message role: developer
# After: works correctly

Closes #24664

Signed-off-by: NIK-TIGER-BILL [email protected]

Changed files

  • litellm/responses/litellm_completion_transformation/transformation.py (modified, +6/-2)

PR #24728: fix(responses): translate 'developer' role to 'system' when bridging to Chat Completions

Description (problem / solution / changelog)

Problem

Fixes #24664

When a client sends a Responses API request (/v1/responses) with messages using the developer role, the Responses API → Chat Completions bridge passes the role through unchanged. Non-OpenAI providers (vLLM, Anthropic, etc.) only recognise system, user, assistant, and tool, so they reject the request with "Unexpected message role".

Root Cause

In _transform_responses_api_input_item_to_chat_completion_message, the role from the input item is forwarded verbatim:

# Before fix
return [
    GenericChatCompletionMessage(
        role=input_item.get("role") or "user",  # "developer" passed through unchanged
        ...
    )
]

The instructions field is already correctly translated to system via transform_instructions_to_system_message, but input items in the conversation history that carry role: "developer" were not.

Fix

Add a one-line translation: map "developer""system" before constructing the GenericChatCompletionMessage.

raw_role = input_item.get("role") or "user"
# Responses API uses "developer" as an alias for "system".
# Non-OpenAI providers only accept "system", so translate it here.
role = "system" if raw_role == "developer" else raw_role

This matches OpenAI's own documentation which states that developer is semantically equivalent to system.

Testing

  • Existing tests pass
  • Added unit test test_developer_role_translated_to_system covering the developer → system mapping

Checklist

  • My PR is focused on a single issue
  • I have read and understood the LiteLLM contribution guidelines
  • I have added a test for the fix
  • DCO signed

Changed files

  • litellm/responses/litellm_completion_transformation/transformation.py (modified, +5/-1)
  • litellm/router_strategy/lowest_latency.py (modified, +79/-69)

Code Example

return [
    GenericChatCompletionMessage(
        role=input_item.get("role") or "user",  # "developer" passed through unchanged
        content=...,
    )
]

---

model_list:
  - model_name: "vllm-default"
    litellm_params:
      model: "openai/default"
      api_base: http://<vllm-host>:8000/v1
      api_key: "your-key"

litellm_settings:
  drop_params: True
  context_window_fallbacks:
    - {"vllm-default": ["openai/gpt-5.2"]}

---

curl -X POST http://litellm:4000/v1/responses \
  -H "Authorization: Bearer sk-..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "vllm-default",
    "input": [
      {"role": "developer", "content": "You are a helpful assistant."},
      {"role": "user", "content": "Hello"}
    ]
  }'

---

role = input_item.get("role") or "user"
if role == "developer":
    role = "system"
return [
    GenericChatCompletionMessage(role=role, content=...)
]

---

litellm.BadRequestError: OpenAIException - {"error":{"message":"Unexpected message role.","type":"BadRequestError","param":null,"code":400}}. Received Model Group=vllm-default
Available Model Group Fallbacks=['openai/gpt-5.2']
Error doing the fallback: litellm.BadRequestError: OpenAIException - {"detail":"Unsupported parameter: metadata"}No fallback model group found for original model_group=openai/gpt-5.2. Fallbacks=[{'vllm-default': ['openai/gpt-5.2']}]. Received Model Group=openai/gpt-5.2
Available Model Group Fallbacks=None
Error doing the fallback: litellm.BadRequestError: OpenAIException - {"detail":"Unsupported parameter: metadata"}No fallback model group found for original model_group=openai/gpt-5.2. Fallbacks=[{'vllm-default': ['openai/gpt-5.2']}]
RAW_BUFFERClick to expand / collapse

Check for existing issues

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

What happened?

When a client sends a Responses API request (/v1/responses) with messages using the developer role (the standard Responses API equivalent of system), LiteLLM's Responses API → Chat Completions bridge passes the developer role through to non-OpenAI providers without translating it to system.

This causes providers like vLLM to reject the request with "Unexpected message role", since they only recognise system, user, assistant, and tool.

The fallback path also fails because the metadata parameter from the Responses API request is forwarded to the Chat Completions call, which downstream providers may not support.

Expected: When bridging Responses API → Chat Completions, developer role should be mapped to system (since they are semantically identical). Additionally, metadata should not be forwarded to the Chat Completions request as it is a Responses API–only parameter.

Root cause in code: In litellm/responses/litellm_completion_transformation/transformation.py, the _transform_responses_api_input_item_to_chat_completion_message method (around line 925) passes roles through as-is:

return [
    GenericChatCompletionMessage(
        role=input_item.get("role") or "user",  # "developer" passed through unchanged
        content=...,
    )
]

The instructions field is correctly translated to system (line 1268 via transform_instructions_to_system_message), but input items in conversation history that carry role: "developer" are not.

Steps to Reproduce

  1. Configure LiteLLM with a vLLM backend:
model_list:
  - model_name: "vllm-default"
    litellm_params:
      model: "openai/default"
      api_base: http://<vllm-host>:8000/v1
      api_key: "your-key"

litellm_settings:
  drop_params: True
  context_window_fallbacks:
    - {"vllm-default": ["openai/gpt-5.2"]}
  1. Send a Responses API request with developer role (any client using @ai-sdk/openai v2+ / Vercel AI SDK will do this by default):
curl -X POST http://litellm:4000/v1/responses \
  -H "Authorization: Bearer sk-..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "vllm-default",
    "input": [
      {"role": "developer", "content": "You are a helpful assistant."},
      {"role": "user", "content": "Hello"}
    ]
  }'
  1. vLLM rejects with "Unexpected message role" because it receives developer instead of system
  2. Fallback to openai/gpt-5.2 also fails with "Unsupported parameter: metadata"

Suggested fix:

role = input_item.get("role") or "user"
if role == "developer":
    role = "system"
return [
    GenericChatCompletionMessage(role=role, content=...)
]

And exclude metadata from the litellm_completion_request dict in transform_responses_api_request_to_chat_completion_request.

Relevant log output

litellm.BadRequestError: OpenAIException - {"error":{"message":"Unexpected message role.","type":"BadRequestError","param":null,"code":400}}. Received Model Group=vllm-default
Available Model Group Fallbacks=['openai/gpt-5.2']
Error doing the fallback: litellm.BadRequestError: OpenAIException - {"detail":"Unsupported parameter: metadata"}No fallback model group found for original model_group=openai/gpt-5.2. Fallbacks=[{'vllm-default': ['openai/gpt-5.2']}]. Received Model Group=openai/gpt-5.2
Available Model Group Fallbacks=None
Error doing the fallback: litellm.BadRequestError: OpenAIException - {"detail":"Unsupported parameter: metadata"}No fallback model group found for original model_group=openai/gpt-5.2. Fallbacks=[{'vllm-default': ['openai/gpt-5.2']}]

What part of LiteLLM is this about?

Proxy

What LiteLLM version are you on ?

1.82.0

Twitter / LinkedIn details

No response

extent analysis

Fix Plan

To resolve the issue, we need to modify the _transform_responses_api_input_item_to_chat_completion_message method to map the developer role to system and exclude the metadata parameter from the litellm_completion_request dict.

Step-by-Step Solution

  1. Update the role mapping:

role = input_item.get("role") or "user" if role == "developer": role = "system" return [ GenericChatCompletionMessage(role=role, content=...) ]

2. **Exclude metadata from the request**:
   In the `transform_responses_api_request_to_chat_completion_request` method, remove the `metadata` parameter from the `litellm_completion_request` dict.
   ```python
# Assuming litellm_completion_request is a dictionary
if 'metadata' in litellm_completion_request:
    del litellm_completion_request['metadata']

Verification

To verify that the fix worked:

  1. Send a Responses API request with the developer role using the same curl command provided in the issue body.
  2. Check the response from the server. It should no longer return an "Unexpected message role" error.
  3. Verify that the fallback path also works by checking the logs for any errors related to the metadata parameter.

Extra Tips

  • Make sure to test the changes thoroughly to ensure that the role mapping and metadata exclusion do not introduce any new issues.
  • Consider adding additional logging or monitoring to detect any similar issues in the future.
  • Review the documentation for the Responses API and Chat Completions bridge to ensure that it accurately reflects the expected behavior.

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