langchain-ai/langchain · error · ValueError

variable {self.variable_name} should be a list of base messa

Error message

variable {self.variable_name} should be a list of base messages, got {value} of type {type(value)}

What it means

MessagesPlaceholder._format_messages requires the value bound to its variable to be a Python list (it may be empty, and may be omitted entirely when optional=True). Any other type — a single BaseMessage, a tuple, a generator, None for a non-optional placeholder — raises ValueError telling you it wants 'a list of base messages'.

Source

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

            **kwargs: Keyword arguments to use for formatting.

        Returns:
            List of `BaseMessage` objects.

        Raises:
            ValueError: If variable is not a list of messages.
        """
        value = (
            kwargs.get(self.variable_name, [])
            if self.optional
            else kwargs[self.variable_name]
        )
        if not isinstance(value, list):
            msg = (
                f"variable {self.variable_name} should be a list of base messages, "
                f"got {value} of type {type(value)}"
            )
            raise ValueError(msg)  # noqa: TRY004
        value = convert_to_messages(value)
        if self.n_messages:
            value = value[-self.n_messages :]
        return value

    @property
    def input_variables(self) -> list[str]:
        """Input variables for this prompt template.

        Returns:
            List of input variable names.
        """
        return [self.variable_name] if not self.optional else []

    @override
    def pretty_repr(self, html: bool = False) -> str:
        """Human-readable representation.

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Always pass a list: {'history': [m1, m2]} or list(history_tuple)
  2. If the value can be absent, declare MessagesPlaceholder('history', optional=True) so kwargs default to []
  3. Convert a single message by wrapping it: {'history': [single_msg]}

Example fix

# before
prompt = ChatPromptTemplate.from_messages([
    MessagesPlaceholder("history"), "human: {q}",
])
prompt.invoke({"history": SystemMessage("be terse"), "q": "hi"})  # ValueError

# after
prompt.invoke({"history": [SystemMessage("be terse")], "q": "hi"})
Defensive patterns

Strategy: type-guard

Validate before calling

from langchain_core.messages import BaseMessage

def coerce_history(value):
    if isinstance(value, BaseMessage):
        return [value]
    if not isinstance(value, list):
        msg = f"history must be a list of messages, got {type(value)}"
        raise ValueError(msg)
    return list(value)

Type guard

def is_message_list(value) -> bool:
    return isinstance(value, list) and all(isinstance(m, BaseMessage) for m in value)

Prevention

When it happens

Trigger: Invoking a ChatPromptTemplate containing MessagesPlaceholder('history') with history=SystemMessage(...), history=(msg1, msg2), or history=msg_generator; passing None when the placeholder is not marked optional=True.

Common situations: Conversation-history wiring: retrieving a single last message instead of a list; passing a tuple from a DB row; forgetting to set optional_messages=True for branches where history may be absent.

Related errors


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