langchain-ai/langchain · error · ValueError

Unexpected input: {message_template}

Error message

Unexpected input: {message_template}

What it means

ChatPromptTemplate.format_messages iterates self.messages and accepts BaseMessage instances, BaseMessagePromptTemplate, or BaseChatPromptTemplate; anything else is rejected with ValueError('Unexpected input: ...'). Type checkers mark the raise unreachable because the messages field is typed to those classes — hitting it at runtime means the field holds an untyped/foreign object, usually injected by direct construction or mutation bypassing validation.

Source

Thrown at libs/core/langchain_core/prompts/chat.py:1199

        Raises:
            ValueError: If messages are of unexpected types.

        Returns:
            List of formatted messages.
        """
        kwargs = self._merge_partial_and_user_variables(**kwargs)
        result = []
        for message_template in self.messages:
            if isinstance(message_template, BaseMessage):
                result.extend([message_template])
            elif isinstance(
                message_template, (BaseMessagePromptTemplate, BaseChatPromptTemplate)
            ):
                message = message_template.format_messages(**kwargs)
                result.extend(message)
            else:
                msg = f"Unexpected input: {message_template}"  # type: ignore[unreachable]
                raise ValueError(msg)  # noqa: TRY004
        return result

    async def aformat_messages(self, **kwargs: Any) -> list[BaseMessage]:
        """Async format the chat template into a list of finalized messages.

        Args:
            **kwargs: Keyword arguments to use for filling in template variables
                in all the template messages in this chat template.

        Returns:
            List of formatted messages.

        Raises:
            ValueError: If unexpected input.
        """
        kwargs = self._merge_partial_and_user_variables(**kwargs)
        result = []
        for message_template in self.messages:

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Keep messages to BaseMessage / message-template objects; convert strings with HumanMessagePromptTemplate.from_template(s) before inserting
  2. Avoid mutating .messages after construction — build a new ChatPromptTemplate via from_messages
  3. If loading from external data, revalidate: reconstruct through from_messages rather than assigning raw lists

Example fix

# before
prompt.messages.append("Summarize the above")  # later format_messages -> ValueError

# after
from langchain_core.prompts import HumanMessagePromptTemplate
prompt.messages.append(HumanMessagePromptTemplate.from_template("Summarize the above"))
Defensive patterns

Strategy: validation

Validate before calling

from langchain_core.messages import BaseMessage
from langchain_core.prompts import BaseMessagePromptTemplate, BaseChatPromptTemplate

def valid_messages(msgs) -> bool:
    return all(
        isinstance(m, (BaseMessage, BaseMessagePromptTemplate, BaseChatPromptTemplate))
        for m in msgs
    )

Type guard

def is_valid_chat_prompt_message(m) -> bool:
    return isinstance(m, (BaseMessage, BaseMessagePromptTemplate, BaseChatPromptTemplate))

Prevention

When it happens

Trigger: Building ChatPromptTemplate(messages=[42]) via model_construct or by mutating .messages after validation; inserting a plain string or custom object into the messages list of an existing template; deserializing a corrupted prompt representation.

Common situations: Dynamic prompt pipelines that append to prompt.messages at runtime; model_construct(...) fast paths that skip validators; interop code that loads prompt state from JSON without re-validation.

Related errors


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