{"record":{"id":"fb26438e0ab79023","repo":"langchain-ai/langchain","slug":"expected-a-single-list-of-messages-got-input-val","errorCode":null,"errorMessage":"Expected a single list of messages. Got {input_val}.","messagePattern":"Expected a single list of messages\\. Got (.+?)\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/core/langchain_core/runnables/history.py","lineNumber":481,"sourceCode":"            input_val = input_val[key]\n\n        # If value is a string, convert to a human message\n        if isinstance(input_val, str):\n            return [HumanMessage(content=input_val)]\n        # If value is a single message, convert to a list\n        if isinstance(input_val, BaseMessage):\n            return [input_val]\n        # If value is a list or tuple...\n        if isinstance(input_val, (list, tuple)):\n            # Handle empty case\n            if len(input_val) == 0:\n                return list(input_val)\n            # If is a list of list, then return the first value\n            # This occurs for chat models - since we batch inputs\n            if isinstance(input_val[0], list):\n                if len(input_val) != 1:\n                    msg = f\"Expected a single list of messages. Got {input_val}.\"\n                    raise ValueError(msg)\n                return input_val[0]\n            return list(input_val)\n        msg = (\n            f\"Expected str, BaseMessage, list[BaseMessage], or tuple[BaseMessage]. \"\n            f\"Got {input_val}.\"\n        )\n        raise ValueError(msg)\n\n    def _get_output_messages(\n        self, output_val: str | BaseMessage | Sequence[BaseMessage] | dict[str, Any]\n    ) -> list[BaseMessage]:\n        # If dictionary, try to pluck the single key representing messages\n        if isinstance(output_val, dict):\n            if self.output_messages_key:\n                key = self.output_messages_key\n            elif len(output_val) == 1:\n                key = next(iter(output_val.keys()))\n            else:","sourceCodeStart":463,"sourceCodeEnd":499,"githubUrl":"https://github.com/langchain-ai/langchain/blob/e32fa9a52eab3b61ad7a45399bfde59b3e580fc4/libs/core/langchain_core/runnables/history.py#L463-L499","documentation":"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.","triggerScenarios":"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.","commonSituations":"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().","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"],"exampleFix":"# before\nwrapped.invoke([[m1], [m2]], config)  # ValueError\n# after\nwrapped.batch([[m1], [m2]], [config, config])\n# or one at a time\nwrapped.invoke([m1], config)","handlingStrategy":"type-guard","validationCode":"msgs = chain_input if isinstance(chain_input, list) else [chain_input]\nif msgs and isinstance(msgs[0], list):\n    assert len(msgs) == 1, \"invoke one batch element at a time, or use .batch()\"","typeGuard":"from langchain_core.messages import BaseMessage\n\ndef is_single_message_batch(v: object) -> bool:\n    return isinstance(v, list) and (not v or isinstance(v[0], BaseMessage))","tryCatchPattern":"try:\n    out = wrapped.invoke(user_input, cfg)\nexcept ValueError as e:\n    if \"single list of messages\" in str(e):\n        outs = wrapped.batch(user_input, [cfg] * len(user_input))","preventionTips":["Use .batch() for multiple inputs on history-wrapped chains","Keep .invoke() inputs to a single str/BaseMessage/list[BaseMessage]"],"tags":["runnable","message-history","batch","input-validation","valueerror"],"backgroundTag":null,"analyzedSha":"e32fa9a52eab3b61ad7a45399bfde59b3e580fc4","analyzedAt":"2026-08-14T18:42:09.092Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}