langchain-ai/langchain · error · ValueError
Runnable without name for tool constructor
Error message
Runnable without name for tool constructor
What it means
When tool() is used as a function to wrap a Runnable (runnable=... keyword), the first positional argument must be the tool name. This error fires when runnable is provided but name_or_callable is empty (None or empty string).
Source
Thrown at libs/core/langchain_core/tools/convert.py:364
extras=extras,
)
return _tool_factory
if len(args) != 0:
# Triggered if a user attempts to use positional arguments that
# do not exist in the function signature
# e.g., @tool("name", runnable, "extra_arg")
# Here, "extra_arg" is not a valid argument
msg = "Too many arguments for tool decorator. A decorator "
raise ValueError(msg)
if runnable is not None:
# tool is used as a function
# for instance tool_from_runnable = tool("name", runnable)
if not name_or_callable:
msg = "Runnable without name for tool constructor"
raise ValueError(msg)
if not isinstance(name_or_callable, str):
msg = "Name must be a string for tool constructor"
raise ValueError(msg)
return _create_tool_factory(name_or_callable)(runnable)
if name_or_callable is not None:
if callable(name_or_callable) and hasattr(name_or_callable, "__name__"):
# Used as a decorator without parameters
# @tool
# def my_tool():
# pass
return _create_tool_factory(name_or_callable.__name__)(name_or_callable)
if isinstance(name_or_callable, str):
# Used with a new name for the tool
# @tool("search")
# def my_tool():
# pass
#
# orView on GitHub (pinned to e32fa9a52e)
Solutions
- Pass a name: tool('my_chain', runnable=my_runnable)
- Or derive it: tool(my_runnable.get_name() or 'fallback_name', runnable=my_runnable)
- Prefer my_runnable.as_tool(name=...) which handles naming itself
Example fix
# before
t = tool(runnable=my_runnable)
# after
t = tool("summarizer", runnable=my_runnable)
# or
t = my_runnable.as_tool(name="summarizer") Defensive patterns
Strategy: validation
Validate before calling
def named_tool(runnable, name: str | None = None):
name = name or runnable.get_name() or "runnable_tool"
if not isinstance(name, str) or not name:
msg = f"Invalid tool name: {name!r}"
raise ValueError(msg)
return tool(name, runnable=runnable) Type guard
def is_valid_tool_name(name: object) -> bool:
return isinstance(name, str) and bool(name.strip()) Try / catch
try:
t = tool(runnable=runnable)
except ValueError as e:
if "without name" in str(e):
t = tool(runnable.get_name() or "runnable_tool", runnable=runnable)
else:
raise Prevention
- Prefer runnable.as_tool(name=...) which defaults naming sensibly
- When generating tools in loops, assert the name variable is a non-empty string first
- Keep a naming helper that falls back to the Runnable's own name
When it happens
Trigger: tool(runnable=my_runnable) with no name; tool('', runnable=my_runnable); tool(None, runnable=my_runnable).
Common situations: Dynamically generating tools from chains in a loop and forgetting the name; assuming the Runnable's own name is used automatically.
Related errors
- Name must be a string for tool constructor
- Runnable must have an object schema.
- Too many arguments for tool decorator. A decorator
- The first argument must be a string or a callable with a __n
- Tool input must be str or dict. If dict, dict arguments must
AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14).
Data as JSON: /api/errors/9044fd640d107716.
Report an issue: GitHub.