langchain-ai/langchain · error · ValueError
Expected 2-tuple of (role, template), got {message}
Error message
Expected 2-tuple of (role, template), got {message} What it means
Raised in _convert_to_message_template when a tuple message does not have exactly 2 elements (role, template). Under static typing this branch is marked unreachable (TypedDict/protocol tuples are length-2), but at runtime a longer or shorter tuple reaches it.
Source
Thrown at libs/core/langchain_core/prompts/chat.py:1466
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(
message_type, template, template_format=template_format
)
else:
message_ = message_type_str(
prompt=PromptTemplate.from_template(
cast("str", template), template_format=template_formatView on GitHub (pinned to e32fa9a52e)
Solutions
- Ensure each tuple message is exactly (role, template).
- If you have extra data, put it in the template construction afterwards or use a typed message object.
- Validate tuple lengths when messages are assembled dynamically.
Example fix
# before
ChatPromptTemplate.from_messages([("user", "hi", "en")])
# after
ChatPromptTemplate.from_messages([("user", "hi")]) Defensive patterns
Strategy: validation
Validate before calling
def valid_message_tuple(m):
return isinstance(m, tuple) and len(m) == 2 Type guard
def is_role_template_pair(m) -> bool:
return isinstance(m, (tuple, list)) and len(m) == 2 and isinstance(m[0], str) Prevention
- Assert length 2 when assembling tuples dynamically.
- Don't append optional third elements to message tuples; carry extras in typed message objects.
When it happens
Trigger: `from_messages([("user", "hi", "extra")])` (3-tuple) or `["user"]` mis-typed as a tuple of one; also `(role, template)` built by unpacking a variable-length list.
Common situations: Appending optional third elements (like a name) to message tuples; zipping config arrays of unequal length producing short tuples.
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 dict to have exact keys 'role' and 'content'. Got:
AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14).
Data as JSON: /api/errors/c4e104af0ced3200.
Report an issue: GitHub.