{"record":{"id":"c15feb920014b722","repo":"langchain-ai/langchain","slug":"the-first-argument-must-be-a-string-or-a-callable","errorCode":null,"errorMessage":"The first argument must be a string or a callable with a __name__ for tool decorator. Got {type(name_or_callable)}","messagePattern":"The first argument must be a string or a callable with a __name__ for tool decorator\\. Got (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/core/langchain_core/tools/convert.py","lineNumber":392,"sourceCode":"            #    pass\n            return _create_tool_factory(name_or_callable.__name__)(name_or_callable)\n        if isinstance(name_or_callable, str):\n            # Used with a new name for the tool\n            # @tool(\"search\")\n            # def my_tool():\n            #    pass\n            #\n            # or\n            #\n            # @tool(\"search\", parse_docstring=True)\n            # def my_tool():\n            #    pass\n            return _create_tool_factory(name_or_callable)\n        msg = (\n            f\"The first argument must be a string or a callable with a __name__ \"\n            f\"for tool decorator. Got {type(name_or_callable)}\"\n        )\n        raise ValueError(msg)\n\n    # Tool is used as a decorator with parameters specified\n    # @tool(parse_docstring=True)\n    # def my_tool():\n    #    pass\n    def _partial(func: Callable[..., Any] | Runnable[Any, Any]) -> BaseTool:\n        \"\"\"Partial function that takes a `Callable` and returns a tool.\"\"\"\n        name_ = func.get_name() if isinstance(func, Runnable) else func.__name__\n        tool_factory = _create_tool_factory(name_)\n        return tool_factory(func)\n\n    return _partial\n\n\ndef _get_description_from_runnable(runnable: Runnable[Any, Any]) -> str:\n    \"\"\"Generate a placeholder description of a `Runnable`.\"\"\"\n    input_schema = runnable.get_input_jsonschema()\n    return f\"Takes {input_schema}.\"","sourceCodeStart":374,"sourceCodeEnd":410,"githubUrl":"https://github.com/langchain-ai/langchain/blob/e32fa9a52eab3b61ad7a45399bfde59b3e580fc4/libs/core/langchain_core/tools/convert.py#L374-L410","documentation":"The first positional argument of @tool must be either a string (tool name) or a callable with __name__ (the function to wrap). Anything else — int, None-likes without __name__, module, list — triggers this ValueError with the offending type.","triggerScenarios":"tool(123); tool(['a','b']); tool(SomeClassWithoutName); passing a variable holding a non-callable as the first argument.","commonSituations":"Programmatic tool creation where a name variable is accidentally None or a non-string; passing a Runnable positionally instead of via runnable=; refactors that change what the first argument holds.","solutions":["Pass a string name or the decorated function itself positionally","For Runnables use tool(name, runnable=runnable)","Sanitize dynamically generated names: assert isinstance(name, str) and name before calling tool()"],"exampleFix":"# before\nname = get_tool_name()          # returns 42 or None\nt = tool(name)(my_func)\n\n# after\nname = get_tool_name()\nassert isinstance(name, str) and name, \"tool name must be a non-empty string\"\nt = tool(name)(my_func)","handlingStrategy":"type-guard","validationCode":"def validate_tool_arg(arg) -> str:\n    if isinstance(arg, str) and arg:\n        return arg\n    if callable(arg) and hasattr(arg, \"__name__\"):\n        return arg.__name__\n    msg = f\"Bad @tool argument: {arg!r} of type {type(arg)}\"\n    raise TypeError(msg)","typeGuard":"def is_valid_first_tool_arg(x: object) -> bool:\n    return (isinstance(x, str) and bool(x)) or (callable(x) and hasattr(x, \"__name__\"))","tryCatchPattern":"try:\n    t = tool(maybe_name)(func)\nexcept ValueError as e:\n    if \"first argument\" in str(e):\n        t = tool(\"default_name\")(func)\n    else:\n        raise","preventionTips":["In dynamic code, branch explicitly on isinstance(name_or_callable, str) before calling tool()","Never pass Runnables positionally; use runnable=","Add type annotations (str | Callable) at tool-factory boundaries so mypy catches misuse"],"tags":["langchain","tools","api-misuse","validation"],"backgroundTag":null,"analyzedSha":"e32fa9a52eab3b61ad7a45399bfde59b3e580fc4","analyzedAt":"2026-08-14T18:42:09.092Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}