sgl-project/sglang · error · ValueError
'role' must be one of {allowed} (case-insensitive).
Error message
'role' must be one of {allowed} (case-insensitive). What it means
Message role normalization: role must be one of the generic message roles (case-insensitive); unknown strings are rejected with the allowed list.
Source
Thrown at python/sglang/srt/entrypoints/openai/protocol.py:707
class ChatCompletionMessageGenericParam(BaseModel):
role: _GenericMessageRole
content: Union[str, List[ChatCompletionMessageContentPart], None] = Field(
default=None
)
tool_call_id: Optional[str] = None
name: Optional[str] = None
reasoning_content: Optional[str] = None
tool_calls: Optional[List[ToolCall]] = Field(default=None, examples=[None])
tools: Optional[List[Tool]] = Field(default=None, examples=[None])
@field_validator("role", mode="before")
@classmethod
def _normalize_role(cls, v):
if isinstance(v, str):
v_lower = v.lower()
if v_lower not in _GENERIC_MESSAGE_ROLES:
allowed = ", ".join(repr(r) for r in _GENERIC_MESSAGE_ROLES)
raise ValueError(f"'role' must be one of {allowed} (case-insensitive).")
return v_lower
raise ValueError("'role' must be a string")
@model_validator(mode="after")
def validate_thinking_parts_role(self):
if self.role != "assistant" and isinstance(self.content, list):
for part in self.content:
if isinstance(part, ChatCompletionMessageContentThinkingPart):
raise ValueError(
"thinking content parts are only valid in assistant messages"
)
return self
class ChatCompletionMessageUserParam(BaseModel):
role: Literal["user"]
content: Union[str, List[ChatCompletionMessageContentPart]]
View on GitHub (pinned to 0132848349)
Solutions
- Use one of the roles printed in the error (e.g. system/user/assistant/tool/developer), lowercase.
- Map custom roles to the nearest standard role client-side before sending.
Example fix
# before
{"role":"bot","content":"hi"}
# after
{"role":"assistant","content":"hi"} Defensive patterns
Strategy: type-guard
Validate before calling
ROLES={'system','user','assistant','tool','developer'}
for m in messages:
assert isinstance(m['role'],str) and m['role'].lower() in ROLES Type guard
def is_valid_role(r): return isinstance(r,str) and r.lower() in {'system','user','assistant','tool','developer'} Prevention
- Lowercase and validate roles before requests.
When it happens
Trigger: role='tool_call', 'bot', 'Tool' (if 'tool' allowed but case rule fails on some path), or any string not in _GENERIC_MESSAGE_ROLES.
Common situations: Custom agent frameworks with invented roles; typos; roles from other provider APIs.
Related errors
- 'role' must be a string
- invalid reasoning effort: {effort!r}
- Value error, parameter top_n should be larger than 0.
- Exactly one of 'prompt' or 'messages' must be provided.
- Assistant tool call function.arguments must be a JSON object
AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28).
Data as JSON: /api/errors/10a426908e105140.
Report an issue: GitHub.