Skip to content

Inconsistent behavior for BaseTool subclasses that return list from _run/_arun #30578

Open
@menezesandre

Description

@menezesandre

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.

if not _is_message_content_type(content):

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 couple of alternatives:

  • 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.3.0: Thu Jan 2 20:24:22 PST 2025; root:xnu-11215.81.4~3/RELEASE_ARM64_T6041
Python Version: 3.13.2 (v3.13.2:4f8bb3947cf, Feb 4 2025, 11:51:10) [Clang 15.0.0 (clang-1500.3.9.4)]

Package Information

langchain_core: 0.3.49
langchain: 0.3.22
langsmith: 0.3.19
langchain_text_splitters: 0.3.7

Optional packages not installed

langserve

Other Dependencies

async-timeout<5.0.0,>=4.0.0;: Installed. No version info available.
httpx: 0.28.1
jsonpatch<2.0,>=1.33: Installed. No version info available.
langchain-anthropic;: Installed. No version info available.
langchain-aws;: Installed. No version info available.
langchain-azure-ai;: Installed. No version info available.
langchain-cohere;: Installed. No version info available.
langchain-community;: Installed. No version info available.
langchain-core<1.0.0,>=0.3.45: Installed. No version info available.
langchain-core<1.0.0,>=0.3.49: Installed. No version info available.
langchain-deepseek;: Installed. No version info available.
langchain-fireworks;: Installed. No version info available.
langchain-google-genai;: Installed. No version info available.
langchain-google-vertexai;: Installed. No version info available.
langchain-groq;: Installed. No version info available.
langchain-huggingface;: Installed. No version info available.
langchain-mistralai;: Installed. No version info available.
langchain-ollama;: Installed. No version info available.
langchain-openai;: Installed. No version info available.
langchain-text-splitters<1.0.0,>=0.3.7: Installed. No version info available.
langchain-together;: Installed. No version info available.
langchain-xai;: Installed. No version info available.
langsmith-pyo3: Installed. No version info available.
langsmith<0.4,>=0.1.125: Installed. No version info available.
langsmith<0.4,>=0.1.17: 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.16
packaging: 24.2
packaging<25,>=23.2: Installed. No version info available.
pydantic: 2.11.1
pydantic<3.0.0,>=2.5.2;: Installed. No version info available.
pydantic<3.0.0,>=2.7.4: Installed. No version info available.
pydantic<3.0.0,>=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.3
requests-toolbelt: 1.0.0
requests<3,>=2: Installed. No version info available.
rich: Installed. No version info available.
SQLAlchemy<3,>=1.4: 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    investigateFlagged for investigation.Ɑ: coreRelated to langchain-core🤖:bugRelated to a bug, vulnerability, unexpected error with an existing feature

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions