langchain-ai/langchain · error · TypeError
Invalid args_schema: expected BaseModel or dict, got {args_s
Error message
Invalid args_schema: expected BaseModel or dict, got {args_schema} What it means
StructuredTool.from_function accepts args_schema only as a pydantic BaseModel class or a JSON-schema-ish dict. Any other type (a TypedDict, an instance instead of a class, a string, a dataclass) raises TypeError with the offending value.
Source
Thrown at libs/core/langchain_core/tools/structured.py:232
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_
and "A base class for creating Pydantic models" in description_
):
description_ = ""
elif not description_:
description_ = None
elif isinstance(args_schema, dict):
description_ = args_schema.get("description")
else:
msg = (
"Invalid args_schema: expected BaseModel or dict, "
f"got {args_schema}"
)
raise TypeError(msg)
if description_ is None:
msg = "Function must have a docstring if description not provided."
raise ValueError(msg)
if description is None:
# Only apply if using the function's docstring
description_ = textwrap.dedent(description_).strip()
# Description example:
# search_api(query: str) - Searches the API for the query.
description_ = f"{description_.strip()}"
return cls(
name=name,
func=func,
coroutine=coroutine,
args_schema=args_schema,
description=description_,
return_direct=return_direct,
response_format=response_format,View on GitHub (pinned to e32fa9a52e)
Solutions
- Pass a pydantic BaseModel subclass: args_schema=MyArgs (class, not instance)
- Or pass a dict schema: args_schema={'title': 'MyArgs', 'type': 'object', 'properties': {...}, 'required': [...]}
- Convert TypedDicts: args_schema=create_model from the TypedDict's annotations, or redeclare as a pydantic model
Example fix
# before
class MyArgs(TypedDict):
query: str
tool = StructuredTool.from_function(fn, args_schema=MyArgs) # TypeError
# after
from pydantic import BaseModel, Field
class MyArgs(BaseModel):
query: str = Field(description="Search query")
tool = StructuredTool.from_function(fn, args_schema=MyArgs) Defensive patterns
Strategy: type-guard
Validate before calling
from pydantic import BaseModel
def is_valid_args_schema(schema: object) -> bool:
return (
(isinstance(schema, type) and issubclass(schema, BaseModel))
or isinstance(schema, dict)
)
# use before construction:
assert is_valid_args_schema(args_schema), f"bad args_schema: {args_schema!r}" Type guard
from pydantic import BaseModel
def is_pydantic_schema_or_dict(x: object) -> bool:
if isinstance(x, type):
return issubclass(x, BaseModel)
return isinstance(x, dict) Try / catch
try:
t = StructuredTool.from_function(fn, args_schema=schema, name="t")
except TypeError as e:
if "Invalid args_schema" in str(e):
from pydantic import create_model
fields = {k: (v, ...) for k, v in schema.__annotations__.items()} # TypedDict case
t = StructuredTool.from_function(
fn, args_schema=create_model("t_args", **fields), name="t"
)
else:
raise Prevention
- Standardize on pydantic BaseModel classes for args_schema in shared code
- Pass the class, never an instance
- Convert TypedDict schemas to pydantic models at module definition time
When it happens
Trigger: StructuredTool.from_function(fn, args_schema=MyTypedDict); passing an instantiated model args_schema=MyModel(...); passing a JSON schema string.
Common situations: Teams using TypedDicts for tool schemas (works with @tool type inference, not here); passing schema instances rather than classes; migrating schemas from JSON strings.
Related errors
- Runnable must have an object schema.
- Tool input must be str or dict. If dict, dict arguments must
- Too many arguments to single-input tool {self.name}.
- Expected a Pydantic model. Got {model}
- Function must have either a docstring or description when in
AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14).
Data as JSON: /api/errors/b395d2f08b2c7de0.
Report an issue: GitHub.