can1357/oh-my-pi · error · TypeError
tool.{self._name}(...) expects a dict of arguments (got {typ
Error message
tool.{self._name}(...) expects a dict of arguments (got {type(args).__name__}) What it means
`_ToolCallable.__call__` merges an optional positional argument with keyword arguments and requires the result to be a dict, since tool arguments travel as a JSON object over the bridge. This TypeError is raised when the positional argument is not a dict (e.g. a list, string, or kwargs-style pile of non-dict values).
Source
Thrown at packages/coding-agent/src/eval/py/prelude.py:439
class _ToolCallable:
"""Invokes one host-side tool via the loopback HTTP bridge."""
__slots__ = ("_name",)
def __init__(self, name: str):
self._name = name
def __repr__(self) -> str:
return f"<tool.{self._name}>"
def __call__(self, args=None, /, **kwargs):
if args is None:
merged: dict = {}
elif isinstance(args, dict):
merged = dict(args)
else:
raise TypeError(
f"tool.{self._name}(...) expects a dict of arguments (got {type(args).__name__})"
)
merged.update(kwargs)
if INTENT_FIELD not in merged:
merged[INTENT_FIELD] = "py prelude"
return _bridge_call(self._name, merged)
class _ToolProxy:
"""`tool.<name>(args)` proxy mirroring the JS runtime bridge."""
__slots__ = ()
def __getattr__(self, name: str) -> _ToolCallable:
if name.startswith("_"):
raise AttributeError(name)
return _ToolCallable(name)
def __getitem__(self, name: str) -> _ToolCallable:View on GitHub (pinned to 9690622007)
Solutions
- Wrap arguments in a dict keyed by the tool's parameter names: `tool.bash({"command": "ls"})`.
- Or use keyword arguments directly: `tool.bash(command="ls")`.
- If args come from a variable, ensure it is a dict before calling (`isinstance(args, dict)`).
Example fix
// before
result = tool.bash("ls -la")
// after
result = tool.bash({"command": "ls -la"})
# or equivalently
result = tool.bash(command="ls -la") Defensive patterns
Strategy: type-guard
Validate before calling
args = {"command": cmd}
if not isinstance(args, dict):
raise SystemExit("tool args must be a dict")
result = tool.bash(args) Type guard
def is_tool_args(args) -> bool:
return isinstance(args, dict) Try / catch
try:
result = tool.bash(cmd)
except TypeError as e:
if "expects a dict of arguments" in str(e):
result = tool.bash({"command": cmd}) Prevention
- Always pass tool arguments as a dict: tool.name({"key": value}).
- Prefer keyword form (tool.name(command="ls")) which sidesteps the positional trap.
- Don't pass JSON strings, lists, or bare values positionally — only dicts merge with kwargs.
When it happens
Trigger: Calling `tool.bash("ls")` instead of `tool.bash({"command": "ls"})`; passing a list like `tool.read_file(["a.txt"])`; positional non-dict values of any type.
Common situations: Porting JS-style calls where args were JSON strings; confusing Python kwargs with the dict form (`tool.bash(command="ls")` is fine via **kwargs, but `tool.bash("ls")` is not); writing helpers that pass through arbitrary user data.
Understand the failure class
Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.
Related errors
- At least one output ID is required
- query cannot be combined with offset/limit
- Output {output_id} is not valid JSON: {e}
- Offset {start_line} is beyond end of output ({total_lines} l
- Output not found: {', '.join(not_found)}\n\nAvailable output
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/912a13a23a6e87de.
Report an issue: GitHub.