langchain-ai/langchain · error · ValueError
Expected dict to have exact keys 'role' and 'content'. Got:
Error message
Expected dict to have exact keys 'role' and 'content'. Got: {message} What it means
Raised in _convert_to_message_template when a dict message passed to from_messages does not have exactly the two keys 'role' and 'content'. Extra keys (e.g. 'name', 'metadata') or missing/rename keys (e.g. 'text' instead of 'content') both trigger it.
Source
Thrown at libs/core/langchain_core/prompts/chat.py:1460
"""
if isinstance(message, (BaseMessagePromptTemplate, BaseChatPromptTemplate)):
message_: BaseMessage | BaseMessagePromptTemplate | BaseChatPromptTemplate = (
message
)
elif isinstance(message, BaseMessage):
message_ = message
elif isinstance(message, str):
message_ = _create_template_from_message_type(
"human", message, template_format=template_format
)
elif isinstance(message, (tuple, dict)):
if isinstance(message, dict):
if set(message.keys()) != {"content", "role"}:
msg = (
"Expected dict to have exact keys 'role' and 'content'."
f" Got: {message}"
)
raise ValueError(msg)
message_type_str = message["role"]
template = message["content"]
else:
if len(message) != 2: # noqa: PLR2004
msg = f"Expected 2-tuple of (role, template), got {message}" # type: ignore[unreachable]
raise ValueError(msg)
message_type_str, template = message
if isinstance(message_type_str, str):
message_ = _create_template_from_message_type(
message_type_str, template, template_format=template_format
)
elif (
hasattr(message_type_str, "model_fields")
and "type" in message_type_str.model_fields
):
message_type = message_type_str.model_fields["type"].default
message_ = _create_template_from_message_type(View on GitHub (pinned to e32fa9a52e)
Solutions
- Reduce each dict to exactly {"role": ..., "content": ...} before passing: {k: m[k] for k in ("role", "content")}.
- For richer messages, construct the typed class instead: HumanMessage(content="hi", name="bob").
- If the extra data matters (tool calls, names), use the appropriate message object rather than the dict shorthand.
Example fix
# before
ChatPromptTemplate.from_messages([
{"role": "user", "content": "hi", "name": "bob"}
])
# after
ChatPromptTemplate.from_messages([
{"role": "user", "content": "hi"}
]) Defensive patterns
Strategy: validation
Validate before calling
def slim_message_dict(m):
if set(m.keys()) != {"role", "content"}:
return {"role": m["role"], "content": m["content"]}
return m Type guard
def is_valid_message_dict(m: dict) -> bool:
return set(m.keys()) == {"role", "content"} Prevention
- Project API-style message dicts down to (role, content) before from_messages.
- Use typed message classes when extra fields (name, tool_calls) must be preserved.
When it happens
Trigger: `ChatPromptTemplate.from_messages([{"role": "user", "content": "hi", "name": "bob"}])` (extra key), or `{"role": "user", "text": "hi"}` (wrong key). The comparison `set(message.keys()) != {"content", "role"}` is exact.
Common situations: Feeding OpenAI/Anthropic API-style message dicts (which legitimately carry extra fields like 'name' or 'tool_calls') straight into from_messages; renaming keys during refactors.
Related errors
- Invalid placeholder template: {template}. Expected a variabl
- Unexpected arguments for placeholder message type. Expected
- Invalid placeholder template: {var_name_wrapped}. Expected a
- Unexpected message type: {message_type}. Use one of 'human',
- Expected 2-tuple of (role, template), got {message}
AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14).
Data as JSON: /api/errors/f82ffa108ff5910b.
Report an issue: GitHub.