langchain-ai/langchain · error · ValueError

Tool arguments must be specified as a dict, received: {res['

Error message

Tool arguments must be specified as a dict, received: {res['args']}

What it means

Raised by PydanticToolsParser.parse_result (non-partial mode) when a parsed tool result's 'args' is not a dict — e.g. the model returned a JSON list, string, or number as the tool arguments. Constructing tool(**res['args']) requires keyword arguments, so a non-mapping args payload is a hard ValueError.

Source

Thrown at libs/core/langchain_core/output_parsers/openai_tools.py:356

        name_dict_v2: dict[str, TypeBaseModel] = {
            tool.model_config.get("title") or tool.__name__: tool
            for tool in self.tools
            if issubclass(tool, BaseModel)
        }
        name_dict_v1: dict[str, TypeBaseModel] = {
            tool.__name__: tool for tool in self.tools if issubclass(tool, BaseModelV1)
        }
        name_dict: dict[str, TypeBaseModel] = {**name_dict_v2, **name_dict_v1}
        pydantic_objects = []
        for res in json_results:
            if not isinstance(res["args"], dict):
                if partial:
                    continue
                msg = (
                    f"Tool arguments must be specified as a dict, received: "
                    f"{res['args']}"
                )
                raise ValueError(msg)

            try:
                tool = name_dict[res["type"]]
            except KeyError as e:
                available = ", ".join(name_dict.keys()) or "<no_tools>"
                msg = (
                    f"Unknown tool type: {res['type']!r}. Available tools: {available}"
                )
                raise OutputParserException(msg) from e

            try:
                pydantic_objects.append(tool(**res["args"]))
            except (ValidationError, ValueError):
                if partial:
                    continue
                has_max_tokens_stop_reason = any(
                    generation.message.response_metadata.get("stop_reason")
                    == "max_tokens"

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Define the tool schema so top-level parameters are a JSON object (properties/type: object), not an array
  2. Improve the prompt/schema so the model always emits an object for arguments
  3. Catch ValueError and retry the call, or pre-validate res['args'] and skip/repair non-dict entries

Example fix

# before
class SearchArgs(BaseModel):
    query: str
# model emitted args as a bare string "cat videos"

# after
# enforce object arguments in the tool description/system prompt:
system = "Tool arguments MUST be a JSON object, e.g. {\"query\": \"...\"}"
Defensive patterns

Strategy: validation

Validate before calling

for res in json_results:
    if not isinstance(res["args"], dict):
        continue  # or repair: {"value": res["args"]}
# only then call the parser

Type guard

def has_dict_args(res: dict) -> bool:
    return isinstance(res.get("args"), dict)

Try / catch

try:
    objs = parser.parse_result(result)
except ValueError as e:
    if "must be specified as a dict" in str(e):
        objs = [o for o in parser.parse_result(result, partial=True) if o is not None]  # skip bad entries

Prevention

When it happens

Trigger: Model emits tool arguments as a JSON array or scalar (e.g. "[1,2]" or "\"text\"") instead of an object; partial=False so the parser cannot silently skip the bad entry.

Common situations: Tool schemas whose parameters are an array at top level (invalid per OpenAI spec but sometimes written); models trained to emit positional arguments; degenerate outputs from small local models.

Related errors


AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14). Data as JSON: /api/errors/11d0d697396732a3. Report an issue: GitHub.