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_format

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Ensure each tuple message is exactly (role, template).
  2. If you have extra data, put it in the template construction afterwards or use a typed message object.
  3. 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

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


AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14). Data as JSON: /api/errors/c4e104af0ced3200. Report an issue: GitHub.