langchain-ai/langchain · error · ValueError
Expected a single list of messages. Got
Error message
Expected a single list of messages. Got {input_val}. What it means
RunnableWithMessageHistory._get_input_messages handles batched chat-model inputs: when the input is a list whose first element is itself a list, it assumes a batch of exactly one and returns that inner list. If there are two or more inner lists it cannot unambiguously pick one, so it raises this ValueError.
Solutions
- Call .batch([...]) on the wrapped chain so each item is routed separately, instead of .invoke([[...], [...]])
- Invoke one message list at a time: chain.invoke([msg], config)
- If input is a single list of messages, ensure elements are BaseMessage objects, not nested lists
Example fix
# before wrapped.invoke([[m1], [m2]], config) # ValueError # after wrapped.batch([[m1], [m2]], [config, config]) # or one at a time wrapped.invoke([m1], config)
Defensive patterns
Strategy: type-guard
Validate before calling
msgs = chain_input if isinstance(chain_input, list) else [chain_input]
if msgs and isinstance(msgs[0], list):
assert len(msgs) == 1, "invoke one batch element at a time, or use .batch()" Type guard
from langchain_core.messages import BaseMessage
def is_single_message_batch(v: object) -> bool:
return isinstance(v, list) and (not v or isinstance(v[0], BaseMessage)) Try / catch
try:
out = wrapped.invoke(user_input, cfg)
except ValueError as e:
if "single list of messages" in str(e):
outs = wrapped.batch(user_input, [cfg] * len(user_input)) Prevention
- Use .batch() for multiple inputs on history-wrapped chains
- Keep .invoke() inputs to a single str/BaseMessage/list[BaseMessage]
When it happens
Trigger: Invoking a RunnableWithMessageHistory-wrapped chain with a batch like [[msg1], [msg2]] passed to .invoke()/.stream() instead of .batch(), so the wrapper sees multiple message lists.
Common situations: Reusing a chat-model-style input shape (list of lists) with the history wrapper; migrating code from direct chat model calls; feeding batch payloads through .invoke().
Related errors
- Expected str, BaseMessage, list[BaseMessage], or…
- Expected keys do not match parameter names of…
- Expected str, BaseMessage, list[BaseMessage], or…
- Missing keys in config['configurable'] Expected keys are…
- Argument 'prompts' is expected to be of type list[str]…
AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14).
Data as JSON: /api/errors/fb26438e0ab79023.
Report an issue: GitHub.
Appendix: source
Thrown at libs/core/langchain_core/runnables/history.py:481
input_val = input_val[key]
# If value is a string, convert to a human message
if isinstance(input_val, str):
return [HumanMessage(content=input_val)]
# If value is a single message, convert to a list
if isinstance(input_val, BaseMessage):
return [input_val]
# If value is a list or tuple...
if isinstance(input_val, (list, tuple)):
# Handle empty case
if len(input_val) == 0:
return list(input_val)
# If is a list of list, then return the first value
# This occurs for chat models - since we batch inputs
if isinstance(input_val[0], list):
if len(input_val) != 1:
msg = f"Expected a single list of messages. Got {input_val}."
raise ValueError(msg)
return input_val[0]
return list(input_val)
msg = (
f"Expected str, BaseMessage, list[BaseMessage], or tuple[BaseMessage]. "
f"Got {input_val}."
)
raise ValueError(msg)
def _get_output_messages(
self, output_val: str | BaseMessage | Sequence[BaseMessage] | dict[str, Any]
) -> list[BaseMessage]:
# If dictionary, try to pluck the single key representing messages
if isinstance(output_val, dict):
if self.output_messages_key:
key = self.output_messages_key
elif len(output_val) == 1:
key = next(iter(output_val.keys()))
else:View on GitHub (pinned to e32fa9a52e)