{"record":{"id":"d7afc74a877c9b56","repo":"PrefectHQ/fastmcp","slug":"str-e-d7afc7","errorCode":null,"errorMessage":"{str(e)}","messagePattern":"\\{str\\(e\\)\\}","errorType":"validation","errorClass":"ValidationError","httpStatus":null,"severity":"warning","filePath":"fastmcp_slim/fastmcp/tools/function_tool.py","lineNumber":439,"sourceCode":"                        f\"Tool '{self.name}' timed out after {self.timeout}s. \"\n                        f\"Consider using task=True for long-running operations. \"\n                        f\"See https://gofastmcp.com/servers/tasks\"\n                    )\n                    raise MCPError(\n                        code=-32000,\n                        message=f\"Tool '{self.name}' execution timed out after {self.timeout}s\",\n                    ) from None\n            else:\n                result = await self._execute(\n                    type_adapter, exec_is_async, arguments, strict=strict\n                )\n        except PydanticValidationError as e:\n            # Body errors are re-raised as _ToolBodyError, so a bare pydantic\n            # ValidationError here is an argument-validation failure (a bad call).\n            # Convert it to fastmcp's ValidationError so the middleware chain and\n            # downstream error taxonomy (e.g. Sentry filters) can treat it as a\n            # client error rather than a server bug.\n            raise ValidationError(str(e), log_level=logging.WARNING) from e\n        except _ToolBodyError as e:\n            # The tool's own body raised a pydantic ValidationError. Surface the\n            # original so it is treated as a server-side error, hiding the\n            # internal sentinel while preserving the error's own chained cause.\n            original = e.__cause__\n            assert original is not None\n            raise original from original.__cause__\n\n        return result\n\n    async def _execute(\n        self,\n        type_adapter: TypeAdapter[Any],\n        exec_is_async: bool,\n        arguments: dict[str, Any],\n        *,\n        strict: bool = False,\n    ) -> Any:","sourceCodeStart":421,"sourceCodeEnd":457,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/tools/function_tool.py#L421-L457","documentation":"Argument-validation failures (pydantic ValidationErrors raised while validating call arguments against the tool's parameter schema) are re-raised as fastmcp ValidationError with log_level WARNING so middleware and error taxonomy treat them as client errors. The raised message is the stringified pydantic error listing which arguments failed validation.","triggerScenarios":"Calling a tool with wrong argument types (e.g. string where int expected), missing required parameters, or extra unknown parameters — anything failing the tool's input schema validation in _run_body.","commonSituations":"LLM clients generating malformed arguments; API changes to a tool's signature while callers cache old schemas; passing JSON numbers as strings; forgetting to coerce nested models.","solutions":["Fix the caller's arguments to match the tool's parameter schema (types, required fields)","Re-fetch the tool schema (list_tools) after any signature change and regenerate the call","Validate arguments client-side with the tool's input schema before invoking"],"exampleFix":"// before\nawait client.call_tool(\"add\", {\"a\": \"1\", \"b\": 2})   # a: str not int\n// after\nawait client.call_tool(\"add\", {\"a\": 1, \"b\": 2})","handlingStrategy":"validation","validationCode":"# validate args against the tool's input schema before calling\ndef args_match_schema(args: dict, input_schema: dict) -> bool:\n    import jsonschema\n    try:\n        jsonschema.validate(args, input_schema)\n        return True\n    except jsonschema.ValidationError:\n        return False","typeGuard":null,"tryCatchPattern":"from fastmcp.exceptions import ValidationError\ntry:\n    result = await client.call_tool('my_tool', args)\nexcept ValidationError as e:\n    logger.warning('bad tool arguments: %s', e)\n    args = fix_args_from_message(str(e), args)\n    result = await client.call_tool('my_tool', args)","preventionTips":["Refresh cached tool schemas after server updates","Coerce JSON strings to numbers where schemas expect numbers","Validate LLM-generated arguments against input_schema before invoking","Keep tool signatures stable; version instead of mutating"],"tags":["validation","pydantic","arguments","client-error"],"backgroundTag":"schema-validation-failed","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}