PrefectHQ/fastmcp · error

Invalid first argument: {type(name_or_fn)}

Error message

Invalid first argument: {type(name_or_fn)}

What it means

The first positional argument of @tool must be a callable (direct decoration), a string (tool name), or None. Anything else (int, dict, function-like object that isn't a routine, etc.) falls through to this TypeError reporting the offending type.

Source

Thrown at fastmcp_slim/fastmcp/tools/function_tool.py:621

            run_in_thread=run_in_thread,
        )
        target = fn.__func__ if isinstance(fn, staticmethod | MethodType) else fn
        cast(Any, target).__fastmcp__ = metadata
        return fn

    def decorator(fn: F, tool_name: str | None) -> F:
        return attach_metadata(fn, tool_name)

    if inspect.isroutine(name_or_fn):
        return decorator(name_or_fn, name)
    elif isinstance(name_or_fn, str):
        if name is not None:
            raise TypeError("Cannot specify name both as first argument and keyword")
        tool_name = name_or_fn
    elif name_or_fn is None:
        tool_name = name
    else:
        raise TypeError(f"Invalid first argument: {type(name_or_fn)}")

    def wrapper(fn: F) -> F:
        return decorator(fn, tool_name)

    return wrapper

View on GitHub (pinned to 1f02114297)

Solutions

  1. Pass a callable to decorate directly: @tool\ndef fn(...)
  2. Pass a string name: @tool("my_name")
  3. Pass nothing: @tool with keyword options only

Example fix

// before
@tool({"name": "x"})
def fn(x: int) -> int: ...
// after
@tool("x")
def fn(x: int) -> int: ...
Defensive patterns

Strategy: type-guard

Validate before calling

def check_tool_first_arg(name_or_fn):
    if name_or_fn is None or isinstance(name_or_fn, str):
        return
    if callable(name_or_fn):
        return
    raise TypeError(f'Invalid first argument: {type(name_or_fn)}')

Type guard

def is_valid_tool_first_arg(x) -> bool:
    return x is None or isinstance(x, str) or (callable(x) and not isinstance(x, (int, dict, list)))

Try / catch

try:
    tool = tool_decorator(x)
except TypeError as e:
    if 'Invalid first argument' in str(e):
        tool = tool_decorator(name=x['name'])(fn)  # recover correct form

Prevention

When it happens

Trigger: @tool(42), @tool(some_config_dict), @tool(instance) where instance is not a routine/string/None — any misuse of the decorator's first positional slot.

Common situations: Passing a configuration object or metadata as the first argument thinking it's the name; accidentally calling @tool(fn_result) instead of @tool; typos like @tool(name) where name is undefined-ish object.

Understand the failure class

Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.

Related errors


AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29). Data as JSON: /api/errors/daf279587f79016b. Report an issue: GitHub.