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

  1. Check the server logs for 'Error reading resource <uri>' with the full traceback to find the underlying exception.
  2. Fix the root cause in the resource handler (file path, network endpoint, credentials).
  3. During debugging, disable masking (mask_error_details=False) so the client message includes the underlying error text.
  4. 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

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


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