agentscope-ai/agentscope · error · TypeError
{type(self).__name__} must be called with keyword arguments
Error message
{type(self).__name__} must be called with keyword arguments only, but got {len(args)} positional argument(s). What it means
Tool.__call__ enforces keyword-only invocation: any positional arguments raise TypeError with their count. Tool arguments must be passed by name so they can be mapped to the tool schema.
Source
Thrown at src/agentscope/tool/_base.py:196
**kwargs: Any,
) -> ToolChunk | AsyncGenerator[ToolChunk, None]:
"""Invoke the tool, layering any registered middlewares around
:meth:`call`.
Tools are always invoked with keyword arguments only. ``*args`` is
accepted in the signature solely to stay Liskov-compatible with
subclasses that override ``__call__`` with their own positional
parameters; any positional argument actually passed here is rejected
(raising :exc:`TypeError`) so it fails loudly instead of being silently
dropped.
Middlewares are applied in an onion fashion: the first registered
middleware is the outermost layer and runs its pre-logic before
any inner layers, then its post-logic after all inner layers
have completed.
"""
if args:
raise TypeError(
f"{type(self).__name__} must be called with keyword arguments "
f"only, but got {len(args)} positional argument(s).",
)
# ``getattr`` with a default so the no-middleware path keeps working
# even if a subclass overrides ``__init__`` without calling
# ``super().__init__()``.
middlewares = getattr(self, "_middlewares", [])
if not middlewares:
if inspect.isasyncgenfunction(self.call):
return self.call(**kwargs)
return await self.call(**kwargs)
async def execute_chain(
index: int = 0,
**chain_kwargs: Any,
) -> AsyncGenerator[ToolChunk, None]:
"""Execute the tool middleware chain."""
if index >= len(middlewares):View on GitHub (pinned to e90f1c7592)
Solutions
- Pass every argument by keyword: my_tool(query='hello')
- Change dynamic invocation to **kwargs: my_tool(**params_dict)
- Update tests/call sites after wrapping functions as tools
Example fix
# before
await my_tool('hello', 5)
# after
await my_tool(query='hello', limit=5) Defensive patterns
Strategy: validation
Validate before calling
assert not args, 'tools accept keyword arguments only'
Try / catch
try:
await tool(*args)
except TypeError as e:
if 'keyword arguments' in str(e):
await tool(**dict(zip(param_names, args)))
else: raise Prevention
- Always invoke tools with **kwargs
- When wrapping functions into tools, update call sites to keyword style
When it happens
Trigger: my_tool('hello') or my_tool('a', 'b') instead of my_tool(query='hello'); also *args unpacking of a tuple instead of **kwargs of a dict.
Common situations: Refactoring from a plain function to a Tool wrapper and keeping positional call sites; dynamic invocation using *args instead of **kwargs.
Related errors
- factory must be a callable, got {type(factory).__name__}
- Input must be a list of Msg objects.
- Expected Msg object, got {type(msg)} instead.
- {self.__class__.__name__} does not implement call
- Ripgrep search timed out after {timeout} seconds. Try search
AI-assisted analysis of agentscope-ai/agentscope@e90f1c7592 (2026-08-28).
Data as JSON: /api/errors/fe3ea240b57a31a8.
Report an issue: GitHub.