{"record":{"id":"b81fbc9d0042bab6","repo":"PrefectHQ/fastmcp","slug":"invalid-roots-handler-handler","errorCode":null,"errorMessage":"Invalid roots handler: {handler}","messagePattern":"Invalid roots handler: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/client/roots.py","lineNumber":42,"sourceCode":"            roots_list.append(r)\n        elif isinstance(r, pydantic.FileUrl):\n            roots_list.append(mcp_types.Root(uri=r))\n        elif isinstance(r, str):\n            roots_list.append(mcp_types.Root(uri=pydantic.FileUrl(r)))\n        else:\n            raise ValueError(f\"Invalid root: {r}\")\n    return roots_list\n\n\ndef create_roots_callback(\n    handler: RootsList | RootsHandler,\n) -> ListRootsFnT:\n    if isinstance(handler, list):\n        return _create_roots_callback_from_roots(handler)\n    elif callable(handler):\n        return _create_roots_callback_from_fn(handler)\n    else:\n        raise ValueError(f\"Invalid roots handler: {handler}\")\n\n\ndef _create_roots_callback_from_roots(\n    roots: RootsList,\n) -> ListRootsFnT:\n    roots = convert_roots_list(roots)\n\n    async def _roots_callback(\n        context: ClientRequestContext,\n    ) -> mcp_types.ListRootsResult:\n        return mcp_types.ListRootsResult(roots=roots)\n\n    return _roots_callback\n\n\ndef _create_roots_callback_from_fn(\n    fn: Callable[[RequestContext[ClientSession, LifespanContextT]], RootsList]\n    | Callable[[RequestContext[ClientSession, LifespanContextT]], Awaitable[RootsList]],","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/client/roots.py#L24-L60","documentation":"ValueError from `create_roots_callback` when the `handler` argument is neither a list of roots nor a callable. The roots API accepts either a static list or a handler function; anything else is rejected.","triggerScenarios":"Calling `client.set_roots(handler)` (or `_bind_restoring_handlers`) with a non-list, non-callable value such as a string, a single Root object, a dict, or None.","commonSituations":"Passing a single root string instead of a one-element list (`set_roots(\"file:///x\")` instead of `set_roots([\"file:///x\"])`); accidentally passing a tuple or generator; a variable that was expected to hold a function but is None.","solutions":["Wrap a single root in a list: `client.set_roots([\"file:///data\"])`","If passing a handler, ensure it is callable (e.g. an async function taking no args and returning roots)","Check that the variable isn't None due to a failed lookup/factory","Convert tuples/generators to `list(...)` before passing"],"exampleFix":"// before\nclient.set_roots(\"file:///data\")  # ValueError\n\n// after\nclient.set_roots([\"file:///data\"])","handlingStrategy":"validation","validationCode":"if not (isinstance(handler, list) or callable(handler)):\n    raise TypeError(f\"handler must be a list or callable, got {type(handler).__name__}\")","typeGuard":"def is_valid_roots_handler(h) -> bool:\n    return isinstance(h, list) or callable(h)","tryCatchPattern":null,"preventionTips":["Wrap single roots in a list before set_roots","Confirm the variable holding your handler is actually a function, not its result","Convert tuples/generators to list first","Add a type annotation: handler: RootsList | RootsHandler"],"tags":["mcp","roots","validation","client"],"backgroundTag":"invalid-argument-type","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}