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
- Prefix the value with a valid scheme, e.g. `file:///data/file.txt` instead of `/data/file.txt`.
- Percent-encode spaces and special characters in the URI (`urllib.parse.quote`).
- Fetch the exact URI from `client.list_resources()` / `list_resource_templates()` instead of constructing it by hand.
- 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
- Always include a scheme (file://, https://, custom scheme) when building URIs
- Percent-encode spaces and reserved characters with urllib.parse.quote
- Copy URIs from list_resources()/list_resource_templates() output instead of hand-writing them
- Validate with AnyUrl(uri) at config-load time, not at call time
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
- mode must be 'legacy', 'auto', or one of {list(MODERN_PROTOC
- Invalid root: {r}
- Invalid roots handler: {handler}
- cache_ttl_seconds must be non-negative, got {ttl_seconds}
- max_cache_size must be non-negative, got {max_size}
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/222d443501c53545.
Report an issue: GitHub.