-
Notifications
You must be signed in to change notification settings - Fork 21.6k
Description
Checked other resources
- I added a very descriptive title to this issue.
- I searched the LangChain documentation with the integrated search.
- I used the GitHub search to find a similar question and didn't find it.
- I am sure that this is a bug in LangChain rather than my code.
- The bug is not resolved by updating to the latest stable version of LangChain (or the specific integration package).
Example Code
from langchain_core.tools import BaseTool
class MyTool(BaseTool):
name: str = "my_tool"
description: str = "This is a tool that does something"
def _run(self, n: int) -> list[dict[str, str]]:
return [{"item": str(i)} for i in range(n)]
my_tool = MyTool()
# In this case, the tool message content is a JSON string.
result = my_tool.run({"n": 1}, tool_call_id="1")
print(result.model_dump(include={"content"})) # {'content': '[{"item": "0"}]'}
# In this case, the tool message content is an empty list (not a JSON string).
# It will be interpreted as an empty message (0 content blocks) rather than a
# message containing an empty list.
result = my_tool.run({"n": 0}, tool_call_id="2")
print(result.model_dump(include={"content"})) # {'content': []}Error Message and Stack Trace (if applicable)
No response
Description
The BaseTool processes the _run output to ensure that a valid message content is returned (a string or a list of message content blocks).
When the tool result is a list, there is an ambiguous scenario when the list is empty. In that case, the result is considered a valid message content (all items in the list are content blocks) and it is not serialized.
langchain/libs/core/langchain_core/tools/base.py
Line 1152 in 46cef90
| if not _is_message_content_type(content): |
langchain/libs/core/langchain_core/tools/base.py
Line 1175 in 46cef90
| isinstance(obj, list) and all(_is_message_content_block(e) for e in obj) |
This is specially problematic because there are a few tools in langchain_community that return lists. E.g. TavilySearchResults can return an empty list and that can result in errors when using the ToolMessage.
I'm not sure what would be the best solution here, a few alternatives:
- consider that the ambiguous case (empty list) is not a message content type, i.e. update
_is_message_content_typeto also check if the list is not empty - allow tools to explicitly state whether the result is a list of message content blocks or a generic list that should be serialized (similar to how we define the
response_format) - forbid the ambiguous scenario (state it in the documentation; have more specific return types for the BaseTool abstract methods; give a warning if the result is a list that does not contain message content blocks)
(this should include reviewing the existing tool integrations)
System Info
System Information
OS: Darwin
OS Version: Darwin Kernel Version 24.5.0: Tue Apr 22 19:53:27 PDT 2025; root:xnu-11417.121.6~2/RELEASE_ARM64_T6041
Python Version: 3.13.2 (main, Feb 5 2025, 18:58:04) [Clang 19.1.6 ]
Package Information
langchain_core: 0.3.66
langsmith: 0.4.4
Optional packages not installed
langserve
Other Dependencies
httpx: 0.28.1
jsonpatch<2.0,>=1.33: Installed. No version info available.
langsmith-pyo3: Installed. No version info available.
langsmith>=0.3.45: Installed. No version info available.
openai-agents: Installed. No version info available.
opentelemetry-api: Installed. No version info available.
opentelemetry-exporter-otlp-proto-http: Installed. No version info available.
opentelemetry-sdk: Installed. No version info available.
orjson: 3.10.18
packaging: 24.2
packaging<25,>=23.2: Installed. No version info available.
pydantic: 2.11.7
pydantic>=2.7.4: Installed. No version info available.
pytest: Installed. No version info available.
PyYAML>=5.3: Installed. No version info available.
requests: 2.32.4
requests-toolbelt: 1.0.0
rich: Installed. No version info available.
tenacity!=8.4.0,<10.0.0,>=8.1.0: Installed. No version info available.
typing-extensions>=4.7: Installed. No version info available.
zstandard: 0.23.0