langchain-ai/langchain · error · ValueError
Function and/or coroutine must be provided
Error message
Function and/or coroutine must be provided
What it means
StructuredTool.from_function uses func or coroutine both as the executable and as the source of the name and schema. With neither provided there is no source_function, so construction aborts with ValueError before any schema inference.
Source
Thrown at libs/core/langchain_core/tools/structured.py:201
TypeError: If the `args_schema` is not a `BaseModel` or dict.
Examples:
```python
def add(a: int, b: int) -> int:
\"\"\"Add two numbers\"\"\"
return a + b
tool = StructuredTool.from_function(add)
tool.run(1, 2) # 3
```
"""
if func is not None:
source_function = func
elif coroutine is not None:
source_function = coroutine
else:
msg = "Function and/or coroutine must be provided"
raise ValueError(msg)
name = name or source_function.__name__
if args_schema is None and infer_schema:
# schema name is appended within function
args_schema = create_schema_from_function(
name,
source_function,
parse_docstring=parse_docstring,
error_on_invalid_docstring=error_on_invalid_docstring,
filter_args=_filter_schema_args(source_function),
)
description_ = description
if description is None and not parse_docstring:
description_ = source_function.__doc__ or None
if description_ is None and args_schema:
if isinstance(args_schema, type) and is_basemodel_subclass(args_schema):
description_ = args_schema.__doc__
if (
description_View on GitHub (pinned to e32fa9a52e)
Solutions
- Supply func (sync) and/or coroutine (async) to from_function
- Guard dynamic construction: raise early if the resolved callable is None
- For pure data tools, subclass StructuredTool and implement _run/_arun instead
Example fix
# before
fn = registry.get(tool_cfg.name) # may return None
tool = StructuredTool.from_function(fn, name=tool_cfg.name)
# after
fn = registry.get(tool_cfg.name)
if fn is None:
msg = f"Unknown tool {tool_cfg.name}"
raise KeyError(msg)
tool = StructuredTool.from_function(fn, name=tool_cfg.name) Defensive patterns
Strategy: validation
Validate before calling
def structured_tool_from(fn, **kw):
if not callable(fn):
msg = f"from_function needs a callable, got {fn!r}"
raise TypeError(msg)
return StructuredTool.from_function(fn, **kw) Type guard
from collections.abc import Callable
def is_tool_source(fn: object) -> bool:
return callable(fn) and hasattr(fn, "__name__") Try / catch
try:
t = StructuredTool.from_function(source, name=name)
except ValueError as e:
if "must be provided" in str(e):
msg = f"Tool source for {name!r} resolved to None"
raise RuntimeError(msg) from e
raise Prevention
- Resolve callables at registration and hard-fail on None instead of forwarding
- Type tool-factory inputs as Callable | Coroutine so None fails static checks
- Write a startup smoke test that instantiates every registered tool
When it happens
Trigger: StructuredTool.from_function() with neither func nor coroutine; conditional code paths that pass func only when a lookup succeeds and silently forward None.
Common situations: Factory functions mapping config entries to tools where the callable registration failed; refactoring from_function calls and dropping the first argument.
Related errors
- Function and/or coroutine must be provided
- Function must have either a docstring or description when in
- The first argument must be a string or a callable with a __n
- StructuredTool does not support sync invocation.
- Function must have a docstring if description not provided.
AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14).
Data as JSON: /api/errors/da09ecebe0f58664.
Report an issue: GitHub.