langchain-ai/langchain · error · ValueError
Invalid placeholder template: {template}. Expected a variabl
Error message
Invalid placeholder template: {template}. Expected a variable name surrounded by curly braces. What it means
Raised in _create_template_from_message_type when a message tuple declares role "placeholder" and the template value is a string that does not start with '{' and end with '}'. A MessagesPlaceholder must reference a variable name surrounded by curly braces, e.g. ("placeholder", "{chat_history}"), so LangChain can extract the variable name.
Source
Thrown at libs/core/langchain_core/prompts/chat.py:1378
message: BaseMessagePromptTemplate = HumanMessagePromptTemplate.from_template(
cast("str", template), template_format=template_format
)
elif message_type in {"ai", "assistant"}:
message = AIMessagePromptTemplate.from_template(
cast("str", template), template_format=template_format
)
elif message_type == "system":
message = SystemMessagePromptTemplate.from_template(
cast("str", template), template_format=template_format
)
elif message_type == "placeholder":
if isinstance(template, str):
if template[0] != "{" or template[-1] != "}":
msg = (
f"Invalid placeholder template: {template}."
" Expected a variable name surrounded by curly braces."
)
raise ValueError(msg)
var_name = template[1:-1]
message = MessagesPlaceholder(variable_name=var_name, optional=True)
else:
try:
var_name_wrapped, is_optional = template
except ValueError as e:
msg = (
"Unexpected arguments for placeholder message type."
" Expected either a single string variable name"
" or a list of [variable_name: str, is_optional: bool]."
f" Got: {template}"
)
raise ValueError(msg) from e
if not isinstance(is_optional, bool):
msg = f"Expected is_optional to be a boolean. Got: {is_optional}"
raise ValueError(msg) # noqa: TRY004
View on GitHub (pinned to e32fa9a52e)
Solutions
- Wrap the variable name in curly braces: change ("placeholder", "history") to ("placeholder", "{history}").
- Alternatively pass the structured form ("placeholder", ["{history}", True]) to also mark it optional.
- Or construct MessagesPlaceholder(variable_name="history") directly instead of the tuple shorthand.
Example fix
# before
ChatPromptTemplate.from_messages([("placeholder", "chat_history")])
# after
ChatPromptTemplate.from_messages([("placeholder", "{chat_history}")]) Defensive patterns
Strategy: validation
Validate before calling
import re
def valid_placeholder_string(t):
return isinstance(t, str) and re.fullmatch(r"\{[a-zA-Z_][a-zA-Z0-9_]*\}", t) is not None Prevention
- Standardize on the {var_name} brace convention for placeholders in code review checklists.
- Prefer MessagesPlaceholder(variable_name=...) when the name comes from a variable.
- Unit-test prompt construction paths that build placeholder tuples dynamically.
When it happens
Trigger: Calling `ChatPromptTemplate.from_messages([("placeholder", "chat_history")])` — missing braces. Also `("placeholder", "chat history")` (spaces instead of braces) or a trailing character like `"{history} "`.
Common situations: Copy-pasting placeholder syntax from older docs or examples that show the bare variable name; refactoring from MessagesPlaceholder(variable_name="history") to tuple form and forgetting to wrap the name in braces.
Related errors
- Unexpected arguments for placeholder message type. Expected
- Invalid placeholder template: {var_name_wrapped}. Expected a
- Expected is_optional to be a boolean. Got: {is_optional}
- Expected variable name to be a string. Got: {var_name_wrappe
- Unexpected message type: {message_type}. Use one of 'human',
AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14).
Data as JSON: /api/errors/a4b5d87d371d9f96.
Report an issue: GitHub.