{"record":{"id":"a0571965ec847936","repo":"PrefectHQ/fastmcp","slug":"first-argument-to-decorator-name-must-be-a-func","errorCode":null,"errorMessage":"First argument to @{decorator_name} must be a function, string, or None, got {type(name_or_fn)}","messagePattern":"First argument to @(.+?) must be a function, string, or None, got (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/apps/app.py","lineNumber":133,"sourceCode":"    name_or_fn: str | AnyFunction | None,\n    name: str | None,\n    register: Callable[[Any, str | None], Any],\n    decorator_name: str,\n) -> Any:\n    \"\"\"Shared dispatch logic for @app.tool() and @app.ui() calling patterns.\"\"\"\n    if inspect.isroutine(name_or_fn):\n        return register(name_or_fn, name)\n\n    if isinstance(name_or_fn, str):\n        if name is not None:\n            raise TypeError(\n                \"Cannot specify both a name as first argument and as keyword argument.\"\n            )\n        tool_name: str | None = name_or_fn\n    elif name_or_fn is None:\n        tool_name = name\n    else:\n        raise TypeError(\n            f\"First argument to @{decorator_name} must be a function, string, or None, \"\n            f\"got {type(name_or_fn)}\"\n        )\n\n    def decorator(fn: F) -> F:\n        return register(fn, tool_name)\n\n    return decorator\n\n\n# ---------------------------------------------------------------------------\n# FastMCPApp\n# ---------------------------------------------------------------------------\n\n\nclass FastMCPApp(Provider):\n    \"\"\"A Provider that represents an MCP application.\n","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/apps/app.py#L115-L151","documentation":"@app.tool() and @app.ui() use _dispatch_decorator to accept a function, a name string, or nothing. Any other first argument (e.g. a bool, dict, class, or an accidentally invoked decorator) cannot be interpreted and raises this TypeError.","triggerScenarios":"Calling `@app.tool(some_object)` where some_object is not a callable routine, string, or None — commonly `@app.tool` misuse like `@app.tool(description=\"...\")`-style kwargs not supported, or `app.tool(True)`, or forgetting parentheses vs adding wrong ones (`@app.tool()` vs `@app.tool`).","commonSituations":"Passing configuration options positionally instead of by keyword; decorating a class or non-function object; double-application where the first application returned something other than a function.","solutions":["Pass only a function, a string tool name, or nothing: `@app.tool`, `@app.tool(\"name\")`, or `@app.tool()`.","Ensure the decorated target is a plain function/routine (use staticmethod-free, plain defs).","Check for stray positional arguments (e.g. moving kwargs like description into the correct supported signature)."],"exampleFix":"// before\n@app.tool({\"name\": \"upload\"})\ndef upload(...): ...\n// after\n@app.tool(\"upload\")\ndef upload(...): ...","handlingStrategy":"type-guard","validationCode":"def is_valid_decorator_arg(x) -> bool:\n    import inspect\n    return x is None or isinstance(x, str) or inspect.isroutine(x)","typeGuard":"import inspect\ndef is_decorator_target(x) -> bool:\n    return x is None or isinstance(x, str) or inspect.isroutine(x)","tryCatchPattern":"try:\n    app.tool(target)\nexcept TypeError as e:\n    if \"First argument to @\" in str(e):\n        raise ValueError(f\"Unsupported decorator target: {target!r}\") from e","preventionTips":["Always decorate plain functions with @app.tool / @app.ui","Use parentheses form @app.tool(\"name\") or @app.tool() only","Pass config options as keywords, never positionally","Check that prior decorator stages return functions, not other objects"],"tags":["python","typeerror","decorator-usage"],"backgroundTag":"invalid-decorator-argument","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}