{"record":{"id":"c8554309806d8b1e","repo":"huggingface/smolagents","slug":"argument-key-has-type-actual-type-but-should","errorCode":null,"errorMessage":"Argument {key} has type '{actual_type}' but should be '{tool.inputs[key]['type']}'","messagePattern":"Argument (.+?) has type '(.+?)' but should be '(.+?)'","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/smolagents/tools.py","lineNumber":1402,"sourceCode":"    \"\"\"\n    if isinstance(arguments, dict):\n        for key, value in arguments.items():\n            if key not in tool.inputs:\n                raise ValueError(f\"Argument {key} is not in the tool's input schema\")\n\n            actual_type = _get_json_schema_type(type(value))[\"type\"]\n            expected_type = tool.inputs[key][\"type\"]\n            expected_type_is_nullable = tool.inputs[key].get(\"nullable\", False)\n\n            # Type is valid if it matches, is \"any\", or is null for nullable parameters\n            if (\n                (actual_type != expected_type if isinstance(expected_type, str) else actual_type not in expected_type)\n                and expected_type != \"any\"\n                and not (actual_type == \"null\" and expected_type_is_nullable)\n            ):\n                if actual_type == \"integer\" and expected_type == \"number\":\n                    continue\n                raise TypeError(f\"Argument {key} has type '{actual_type}' but should be '{tool.inputs[key]['type']}'\")\n\n        for key, schema in tool.inputs.items():\n            key_is_nullable = schema.get(\"nullable\", False)\n            if key not in arguments and not key_is_nullable:\n                raise ValueError(f\"Argument {key} is required\")\n        return None\n    else:\n        expected_type = list(tool.inputs.values())[0][\"type\"]\n        if _get_json_schema_type(type(arguments))[\"type\"] != expected_type and not expected_type == \"any\":\n            raise TypeError(f\"Argument has type '{type(arguments).__name__}' but should be '{expected_type}'\")\n\n\n__all__ = [\n    \"AUTHORIZED_TYPES\",\n    \"Tool\",\n    \"tool\",\n    \"load_tool\",\n    \"launch_gradio_demo\",","sourceCodeStart":1384,"sourceCodeEnd":1420,"githubUrl":"https://github.com/huggingface/smolagents/blob/30bb1161095dbae2271e6bc3cc4c219cc3897a57/src/smolagents/tools.py#L1384-L1420","documentation":"Raised by smolagents' validate_tool_arguments when an argument passed to a tool does not match the JSON Schema type declared in the tool's inputs definition. It is the library's pre-execution guard so that tool forward() methods receive correctly typed values. Integer values are accepted where 'number' is expected, and 'any' or nullable schemas bypass the check.","triggerScenarios":"Calling a Tool (or an agent making a tool call) with, e.g., a string '5' where inputs declare {'type': 'integer'}, or a dict where 'array' is declared. Also triggered by argument keys not present in the tool's inputs whose type cannot be validated.","commonSituations":"LLM models returning numbers as strings, booleans as 'true', or lists as comma-separated strings; mismatch between the tool author's declared input types and what the model actually emits; custom tools with hand-written input schemas that don't match the Python signatures.","solutions":["Fix the arguments to match the declared type (e.g., convert '5' to 5 before calling the tool)","Adjust the tool's inputs declaration to the type actually received, or set 'type': 'any' / 'nullable': True where appropriate","If a model keeps emitting wrong types, tighten the tool description or prompt so the model produces correctly typed JSON","For integer-tolerant float inputs, note ints are allowed for 'number' but not vice versa; cast in your wrapper"],"exampleFix":"# before\ntool = Tool(name='add', inputs={'a': {'type': 'integer'}}, ...)\ntool(a='5')  # TypeError\n\n# after\ntool(a=int('5'))\n# or declare: inputs={'a': {'type': 'any'}}","handlingStrategy":"validation","validationCode":"import json\ndef validate_args(tool, arguments):\n    type_map = {str: 'string', int: 'integer', float: 'number', bool: 'boolean', list: 'array', dict: 'object'}\n    for key, schema in tool.inputs.items():\n        if key in arguments and isinstance(schema.get('type'), str):\n            expected = schema['type']\n            if expected == 'any':\n                continue\n            actual = type_map.get(type(arguments[key]))\n            if actual and actual != expected and not (actual == 'integer' and expected == 'number'):\n                raise ValueError(f'{key}: expected {expected}, got {actual}')\n    return arguments","typeGuard":"def args_match(tool, arguments: dict) -> bool:\n    tm = {str: 'string', int: 'integer', float: 'number', bool: 'boolean', list: 'array', dict: 'object'}\n    return all(\n        s.get('type') == 'any' or tm.get(type(arguments.get(k))) == s.get('type')\n        or (tm.get(type(arguments.get(k))) == 'integer' and s.get('type') == 'number')\n        for k, s in tool.inputs.items() if k in arguments\n    )","tryCatchPattern":"try:\n    result = tool(**arguments)\nexcept TypeError as e:\n    if 'has type' in str(e):\n        # coerce types from the message and retry, or log and surface to the model\n        raise","preventionTips":["Declare tool input types precisely and match them to forward() annotations","Test each tool with representative argument dicts","Mark flexible inputs as 'any' or 'nullable' deliberately"],"tags":["smolagents","tool-calling","type-validation","json-schema"],"backgroundTag":"argument-type-mismatch","analyzedSha":"30bb1161095dbae2271e6bc3cc4c219cc3897a57","analyzedAt":"2026-08-28T18:52:54.169Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}