microsoft/autogen · error · ValueError
Unrecognized message role: {message.role}
Error message
Unrecognized message role: {message.role} What it means
parse_sampling_message maps MCP sampling messages to AutoGen messages and accepts only role 'user' or 'assistant'; any other role string raises ValueError(f'Unrecognized message role: {message.role}'). The MCP sampling spec only defines these two roles, so this error indicates a malformed or protocol-violating message from the server.
Source
Thrown at python/packages/autogen-ext/src/autogen_ext/tools/mcp/_host/_sampling.py:85
Raises:
ValueError: If message role is not recognized
AssertionError: If assistant message content is not text
"""
content = parse_sampling_content(message.content, model_info=model_info)
if message.role == "user":
return UserMessage(
source="user",
content=[content],
)
elif message.role == "assistant":
assert isinstance(content, str), "Assistant messages only support string content."
return AssistantMessage(
source="assistant",
content=content,
)
else:
raise ValueError(f"Unrecognized message role: {message.role}")
def finish_reason_to_stop_reason(finish_reason: FinishReasons) -> StopReason:
"""Convert AutoGen finish reasons to MCP stop reasons.
Args:
finish_reason: AutoGen completion finish reason
Returns:
Corresponding MCP stop reason
"""
if finish_reason == "stop":
return "endTurn"
elif finish_reason == "length":
return "maxTokens"
else:
return finish_reason
View on GitHub (pinned to 027ecf0a37)
Solutions
- Fix the server to send only role 'user' or 'assistant' in sampling messages (system prompts go in the separate systemPrompt field of the sampling request).
- If a system prompt is intended, move it into the sampling request's systemPrompt parameter instead of a message entry.
- Upgrade the server library (e.g. official typescript/python MCP SDK) which enforces the role union.
- As a host-side mitigation, catch the ValueError per message and reject that sampling request cleanly.
Example fix
# server side — before
messages = [types.SamplingMessage(role="system", content=text_block)]
# server side — after
result = await session.create_message(
messages=[types.SamplingMessage(role="user", content=text_block)],
system_prompt="You are a helpful assistant.
max_tokens=1024,
) Defensive patterns
Strategy: validation
Validate before calling
ALLOWED_ROLES = {"user", "assistant"}
if message.role not in ALLOWED_ROLES:
raise ValueError(f"sampling message role must be one of {sorted(ALLOWED_ROLES)}, got {message.role!r}") Type guard
from typing import Any, TypeGuard
def is_supported_sampling_role(role: Any) -> TypeGuard[str]:
return role in {"user", "assistant"} Try / catch
try:
msg = parse_sampling_message(message, model_info)
except ValueError as e:
if "Unrecognized message role" in str(e):
return error_result("malformed sampling message")
raise Prevention
- Build servers with the official MCP SDK, which enforces the role union at type level.
- Put system prompts in the sampling request's systemPrompt field, never as a message.
- Validate inbound sampling payloads in the host before conversion.
When it happens
Trigger: An MCP server sends a sampling message with role='system', 'tool', 'function', or a custom string; parse_sampling_message falls through user/assistant branches and raises.
Common situations: A hand-written or experimental MCP server reusing LLM chat roles (system/tool) in createMessage payloads; server code built against a different understanding of the sampling schema; typos like 'User'.
Related errors
- Unsupported content type: {content.type}
- model {model_family} does not support vision.
- Failed to list MCP tools
- Failed to call MCP tool
- MCP health check failed
AI-assisted analysis of microsoft/autogen@027ecf0a37 (2026-08-15).
Data as JSON: /api/errors/fd633890dc7ed2f0.
Report an issue: GitHub.