PrefectHQ/fastmcp · error · ResourceError
Error reading resource {uri!r}
Error message
Error reading resource {uri!r} What it means
FastMCP raises ResourceError("Error reading resource {uri!r}") when reading a resource raised an unexpected exception and error masking is enabled (`mask_error_details=True`). The original exception is hidden and chained as __cause__; details remain in server logs via logger.exception. It is the library's way of preventing internal details from leaking to LLM clients.
Source
Thrown at fastmcp_slim/fastmcp/server/server.py:1653
)
raise
except MCPError:
logger.exception(f"Error reading resource {uri!r}")
raise
except Exception as e:
logger.exception(f"Error reading resource {uri!r}")
# Handle actionable errors that should reach the LLM
if get_http_status_code(e) == 429:
raise ResourceError(
"Rate limited by upstream API, please retry later"
) from e
if is_timeout_error(e):
raise ResourceError(
"Upstream request timed out, please retry"
) from e
# Standard masking logic
if self._mask_error_details:
raise ResourceError(
f"Error reading resource {uri!r}"
) from e
raise ResourceError(
f"Error reading resource {uri!r}: {e}"
) from e
# Try templates (transforms + auth via get_resource_template)
template = await self.get_resource_template(uri, version=version)
if template is None:
if version is None:
raise NotFoundError(f"Unknown resource: {uri!r}")
raise NotFoundError(
f"Unknown resource: {uri!r} version {version!r}"
)
span.set_attributes(template.get_span_attributes())
params = template.matches(uri)
assert params is not None
View on GitHub (pinned to 1f02114297)
Solutions
- Check the server logs for 'Error reading resource <uri>' with the full traceback to find the underlying exception.
- Fix the root cause in the resource handler (file path, network endpoint, credentials).
- During debugging, disable masking (mask_error_details=False) so the client message includes the underlying error text.
- If the failure is expected, raise a FastMCPError/ResourceError subclass from the handler with a client-appropriate message so it passes through unmasked.
Example fix
// before: server = FastMCP(mask_error_details=True) # client sees only "Error reading resource 'file:///data.csv'"
// after: server = FastMCP(mask_error_details=False) # or fix handler:
# before
def load():
return open(MISSING_PATH).read()
# after
@resource("data://csv")
def load():
try:
return open(DATA_PATH).read()
except FileNotFoundError as e:
raise ResourceError("CSV data file is not yet generated") from e Defensive patterns
Strategy: try-catch
Validate before calling
// ensure the resource exists before reading
resources = await client.list_resources()
assert any(str(r.uri) == uri for r in resources), f"{uri} not exposed by server" Try / catch
try:
result = await client.read_resource(uri)
except ResourceError as e:
if 'Error reading resource' in str(e):
logger.error(f"masked resource failure for {uri}; check server logs", exc_info=e)
raise Prevention
- Keep mask_error_details=False in dev so failures are self-explanatory.
- Raise typed FastMCP errors from handlers for expected failures so they bypass masking.
- Monitor server logs, which always carry the unmasked traceback.
- Wrap risky I/O in handlers with specific exception handling.
When it happens
Trigger: Calling `await server.read_resource(uri)` (directly or via `_on_read_resource`/client `read_resource`) where the concrete resource's `_read()` raises a non-FastMCP, non-MCPError exception (e.g. OSError, HTTP error that isn't 429 or a timeout) and the server was constructed with mask_error_details=True.
Common situations: Resource functions hitting a filesystem/DB/network failure in production with error masking on; developers confused why the client shows a generic message while logs hold the real cause; environments where an upstream API URL/key is misconfigured.
Related errors
- Error reading resource {uri!r}: {e}
- The client negotiated a modern protocol era (server/discover
- logging/setLevel is not available on MCP 2026-07-28 connecti
- Unsupported content type: {type(item)}
- Remote server returned empty content for {parameterized_uri}
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/2eb3f13f053d335b.
Report an issue: GitHub.