PrefectHQ/fastmcp · error · ValueError

Provided resource URI is invalid: {str(uri)!r}

Error message

Provided resource URI is invalid: {str(uri)!r}

What it means

`ClientResourcesMixin.read_resource()` accepts a URI as `str` or `AnyUrl`; when a string is passed it is coerced via `AnyUrl(uri)`. If that parse fails, the client raises `ValueError` wrapping the original exception, because MCP resources must be addressed by a valid URI. The rejection happens before any network request is sent.

Source

Thrown at fastmcp_slim/fastmcp/client/mixins/resources.py:301

                A list of content objects.

        Raises:
            RuntimeError: If called while the client is not connected.
            MCPError: If the request results in a TimeoutError | JSONRPCError
        """
        # Merge version into request-level meta (not arguments)
        request_meta = dict(meta) if meta else {}
        if version is not None:
            request_meta["fastmcp"] = {
                **request_meta.get("fastmcp", {}),
                "version": version,
            }

        if isinstance(uri, str):
            try:
                uri = AnyUrl(uri)  # Ensure AnyUrl
            except Exception as e:
                raise ValueError(
                    f"Provided resource URI is invalid: {str(uri)!r}"
                ) from e
        result = await self.read_resource_mcp(uri, meta=request_meta or None)
        return result.contents

View on GitHub (pinned to 1f02114297)

Solutions

  1. Prefix the value with a valid scheme, e.g. `file:///data/file.txt` instead of `/data/file.txt`.
  2. Percent-encode spaces and special characters in the URI (`urllib.parse.quote`).
  3. Fetch the exact URI from `client.list_resources()` / `list_resource_templates()` instead of constructing it by hand.
  4. Validate the string with `AnyUrl(uri)` (pydantic) before calling `read_resource`.

Example fix

// before
contents = await client.read_resource("/data/config.json")  # ValueError
// after
from urllib.parse import quote
uri = f"file:///{quote('/data/config.json')}"
contents = await client.read_resource(uri)  # or pass AnyUrl(uri)
Defensive patterns

Strategy: validation

Validate before calling

from pydantic import AnyUrl

def is_valid_resource_uri(uri: str) -> bool:
    try:
        AnyUrl(uri)
        return bool(uri.split(":", 1)[0])  # non-empty scheme
    except Exception:
        return False

# before calling:
# if not is_valid_resource_uri(candidate):
#     raise ValueError(f"Not a valid resource URI: {candidate!r}")

Type guard

from pydantic import AnyUrl

def as_resource_uri(uri: str) -> AnyUrl | None:
    try:
        return AnyUrl(uri)
    except Exception:
        return None

Try / catch

try:
    contents = await client.read_resource(uri)
except ValueError as e:
    if "resource URI is invalid" in str(e):
        logger.error("Bad resource URI: %s", e)
        contents = None  # or look up the real URI via list_resources()
    else:
        raise

Prevention

When it happens

Trigger: Calling `await client.read_resource("not-a-uri")`, passing a bare path like `"/data/file.txt"` without a scheme, a URI with illegal characters or spaces, or an empty string.

Common situations: Building URIs by string concatenation and forgetting the scheme prefix; hardcoding URIs with unescaped spaces or special characters; passing a resource name instead of its URI; config files that store relative paths rather than full URIs.

Related errors


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