langchain-ai/langchain · error · ValueError
Unexpected message type: {message_type}. Use one of 'human',
Error message
Unexpected message type: {message_type}. Use one of 'human', 'user', 'ai', 'assistant', or 'system'. What it means
Raised in _create_template_from_message_type when the message role string is not one of the recognized types: 'human'/'user', 'ai'/'assistant', 'system', or 'placeholder'. The role comes from the first element of a (role, template) tuple or the 'role' key of a dict message.
Source
Thrown at libs/core/langchain_core/prompts/chat.py:1414
if not isinstance(var_name_wrapped, str):
msg = f"Expected variable name to be a string. Got: {var_name_wrapped}"
raise ValueError(msg) # noqa: TRY004
if var_name_wrapped[0] != "{" or var_name_wrapped[-1] != "}":
msg = (
f"Invalid placeholder template: {var_name_wrapped}."
" Expected a variable name surrounded by curly braces."
)
raise ValueError(msg)
var_name = var_name_wrapped[1:-1]
message = MessagesPlaceholder(variable_name=var_name, optional=is_optional)
else:
msg = (
f"Unexpected message type: {message_type}. Use one of 'human',"
f" 'user', 'ai', 'assistant', or 'system'."
)
raise ValueError(msg)
return message
def _convert_to_message_template(
message: MessageLikeRepresentation,
template_format: PromptTemplateFormat = "f-string",
) -> BaseMessage | BaseMessagePromptTemplate | BaseChatPromptTemplate:
"""Instantiate a message from a variety of message formats.
A message can be represented using the following formats:
1. `BaseMessagePromptTemplate`
2. `BaseMessage`
3. 2-tuple of `(message type, template)`; e.g., `('human', '{user_input}')`
4. 2-tuple of `(message class, template)`
5. A string which is shorthand for `('human', template)`; e.g., `'{user_input}'`
Args:View on GitHub (pinned to e32fa9a52e)
Solutions
- Map the role to an accepted one: 'bot'->'ai', 'user'->'human', 'assistant'->'ai'.
- For tool/function messages, pass the actual message class (ToolMessage(...)) instead of a role tuple.
- Normalize role strings to lowercase and validate against the accepted set before building the prompt.
Example fix
# before
ChatPromptTemplate.from_messages([("bot", "hi")])
# after
ChatPromptTemplate.from_messages([("ai", "hi")]) Defensive patterns
Strategy: validation
Validate before calling
ACCEPTED_ROLES = {"human", "user", "ai", "assistant", "system", "placeholder"}
def normalize_role(role):
r = role.lower()
aliases = {"bot": "ai", "model": "ai", "tool": None}
return aliases.get(r, r if r in ACCEPTED_ROLES else None) Type guard
def is_supported_role(role: str) -> bool:
return role in {"human", "user", "ai", "assistant", "system", "placeholder"} Try / catch
try:
prompt = ChatPromptTemplate.from_messages(messages)
except ValueError as e:
if "Unexpected message type" in str(e):
# log offending role and map/fix it
raise
raise Prevention
- Map external role vocabularies (OpenAI, Anthropic, app-specific) to LangChain roles at the boundary.
- Lowercase and validate role strings from user/config input before building prompts.
- Use typed message objects for roles with no tuple equivalent (tool, function).
When it happens
Trigger: `ChatPromptTemplate.from_messages([("bot", "hi")])`, `[{"role": "tool", "content": ...}]`, or a typo like "System" (capitalized) or "aı" — none are mapped. Note 'tool' and 'placeholder' handling differs: only the listed roles are accepted here.
Common situations: Porting OpenAI-style message lists (which allow 'tool' and 'function' roles) into from_messages; typos and case mismatches; role strings sourced from user input or a database.
Related errors
- Invalid placeholder template: {template}. Expected a variabl
- Unexpected arguments for placeholder message type. Expected
- Invalid placeholder template: {var_name_wrapped}. Expected a
- Expected dict to have exact keys 'role' and 'content'. Got:
- Expected 2-tuple of (role, template), got {message}
AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14).
Data as JSON: /api/errors/2005e2ee95a2a0a6.
Report an issue: GitHub.