PrefectHQ/fastmcp · error · ValueError
Invalid roots handler: {handler}
Error message
Invalid roots handler: {handler} What it means
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.
Source
Thrown at fastmcp_slim/fastmcp/client/roots.py:42
roots_list.append(r)
elif isinstance(r, pydantic.FileUrl):
roots_list.append(mcp_types.Root(uri=r))
elif isinstance(r, str):
roots_list.append(mcp_types.Root(uri=pydantic.FileUrl(r)))
else:
raise ValueError(f"Invalid root: {r}")
return roots_list
def create_roots_callback(
handler: RootsList | RootsHandler,
) -> ListRootsFnT:
if isinstance(handler, list):
return _create_roots_callback_from_roots(handler)
elif callable(handler):
return _create_roots_callback_from_fn(handler)
else:
raise ValueError(f"Invalid roots handler: {handler}")
def _create_roots_callback_from_roots(
roots: RootsList,
) -> ListRootsFnT:
roots = convert_roots_list(roots)
async def _roots_callback(
context: ClientRequestContext,
) -> mcp_types.ListRootsResult:
return mcp_types.ListRootsResult(roots=roots)
return _roots_callback
def _create_roots_callback_from_fn(
fn: Callable[[RequestContext[ClientSession, LifespanContextT]], RootsList]
| Callable[[RequestContext[ClientSession, LifespanContextT]], Awaitable[RootsList]],View on GitHub (pinned to 1f02114297)
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
Example fix
// before
client.set_roots("file:///data") # ValueError
// after
client.set_roots(["file:///data"]) Defensive patterns
Strategy: validation
Validate before calling
if not (isinstance(handler, list) or callable(handler)):
raise TypeError(f"handler must be a list or callable, got {type(handler).__name__}") Type guard
def is_valid_roots_handler(h) -> bool:
return isinstance(h, list) or callable(h) Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
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
- Invalid root: {r}
- INVALID_PARAMS
- mode must be 'legacy', 'auto', or one of {list(MODERN_PROTOC
- [{self.name}] Reached auto-pagination limit ({max_pages} pag
- [{self.name}] Reached auto-pagination limit ({max_pages} pag
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/b81fbc9d0042bab6.
Report an issue: GitHub.