langchain-ai/langchain · error · NotImplementedError

Unsupported operand type for +: {type(other)}

Error message

Unsupported operand type for +: {type(other)}

What it means

ChatPromptTemplate.__add__ supports concatenating a string, list, or tuple of messages/templates on the right side; anything else raises NotImplementedError('Unsupported operand type for +: {type}'). This operator is a convenience for extending a prompt, not general addition — ints, dicts, other prompt objects (non-chat), or Runnables are rejected.

Source

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

            )
        if isinstance(
            other, (BaseMessagePromptTemplate, BaseMessage, BaseChatPromptTemplate)
        ):
            return ChatPromptTemplate(messages=[*self.messages, other]).partial(
                **partials
            )
        if isinstance(other, (list, tuple)):
            other_ = ChatPromptTemplate.from_messages(other)
            return ChatPromptTemplate(messages=self.messages + other_.messages).partial(
                **partials
            )
        if isinstance(other, str):
            prompt = HumanMessagePromptTemplate.from_template(other)
            return ChatPromptTemplate(messages=[*self.messages, prompt]).partial(
                **partials
            )
        msg = f"Unsupported operand type for +: {type(other)}"
        raise NotImplementedError(msg)

    @model_validator(mode="before")
    @classmethod
    def validate_input_variables(cls, values: dict[str, Any]) -> Any:
        """Validate input variables.

        If `input_variables` is not set, it will be set to the union of all input
        variables in the messages.

        Args:
            values: values to validate.

        Returns:
            Validated values.

        Raises:
            ValueError: If input variables do not match.
        """

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Wrap the right side in a list: prompt + [message_or_template]
  2. For plain text, add the string directly: prompt + "Summarize the above" (becomes a human message)
  3. To compose two ChatPromptTemplates, use ChatPromptTemplate.from_messages([*p1.messages, *p2.messages])

Example fix

# before
merged = base_prompt + followup_prompt  # NotImplementedError (not str/list/tuple path)

# after
merged = ChatPromptTemplate.from_messages(
    [*base_prompt.messages, *followup_prompt.messages]
)
Defensive patterns

Strategy: type-guard

Validate before calling

def add_to_prompt(prompt, other):
    if isinstance(other, (str, list, tuple)):
        return prompt + other
    msg = f"cannot add {type(other)} to ChatPromptTemplate; wrap in a list"
    raise TypeError(msg)

Type guard

def is_addable_to_chat_prompt(other) -> bool:
    return isinstance(other, (str, list, tuple))

Try / catch

try:
    merged = prompt + other
except NotImplementedError:
    merged = prompt + [other]  # wrap and retry

Prevention

When it happens

Trigger: prompt + 5, prompt + {'role': ...}, prompt + some_string_generator, or prompt + another_prompt where the right side is not one of str/list/tuple. Note a bare dict is NOT accepted even though from_messages accepts dict elements inside a list.

Common situations: Developers assume prompt1 + prompt2 composes two ChatPromptTemplates; or splat a **kwargs dict onto +; or add a single message object instead of wrapping it in a list.

Related errors


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