PrefectHQ/fastmcp · warning · ToolError

Rate limited by upstream API, please retry later

Error message

Rate limited by upstream API, please retry later

What it means

In call_tool's generic exception handler, any unexpected exception from tool._run whose HTTP status code is 429 is converted to ToolError('Rate limited by upstream API, please retry later'). FastMCP recognizes rate-limit errors as actionable even when error masking is enabled, so the LLM/client learns it should back off and retry.

Source

Thrown at fastmcp_slim/fastmcp/server/server.py:1545

                    # it says the request cannot be serviced at all, and
                    # SEP-2575 requires it on the wire as -32021 (HTTP 400).
                    # Flattening it into a result would drop the code and tell
                    # the client the call had succeeded.
                    if (
                        isinstance(e, MCPError)
                        and e.error.code == MISSING_REQUIRED_CLIENT_CAPABILITY
                    ):
                        logger.debug(
                            "Tool %r requires a client capability the client did "
                            "not declare",
                            name,
                        )
                        raise
                    logger.exception(f"Error calling tool {name!r}")
                    # Handle actionable errors that should reach the LLM
                    # even when masking is enabled
                    if get_http_status_code(e) == 429:
                        raise ToolError(
                            "Rate limited by upstream API, please retry later"
                        ) from e
                    if is_timeout_error(e):
                        raise ToolError(
                            "Upstream request timed out, please retry"
                        ) from e
                    # Standard masking logic
                    if self._mask_error_details:
                        raise ToolError(f"Error calling tool {name!r}") from e
                    raise ToolError(f"Error calling tool {name!r}: {e}") from e

    async def read_resource(
        self,
        uri: str,
        *,
        version: VersionSpec | None = None,
        run_middleware: bool = True,
    ) -> ResourceResult:

View on GitHub (pinned to 1f02114297)

Solutions

  1. Retry the call after a delay with exponential backoff (the error explicitly invites retry later)
  2. Reduce call frequency or batch requests to the upstream API
  3. Use a higher-quota API key/tier or rotate across keys
  4. Cache upstream responses in the tool to cut request volume
  5. Inspect the chained exception (the 429 cause) to see which upstream limit was hit

Example fix

// before: tight retry loop
for _ in range(10):
    await client.call_tool('search_web', {'q': '...'})
// after: backoff on the rate-limit ToolError
import asyncio
for attempt in range(5):
    try:
        return await client.call_tool('search_web', {'q': '...'})
    except ToolError as e:
        if 'Rate limited' not in str(e):
            raise
        await asyncio.sleep(2 ** attempt)
Defensive patterns

Strategy: retry

Type guard

def is_rate_limited(e: BaseException) -> bool:
    return isinstance(e, ToolError) and 'Rate limited' in str(e)

Try / catch

import asyncio
for attempt in range(5):
    try:
        return await client.call_tool('my_tool', args)
    except ToolError as e:
        if 'Rate limited' not in str(e):
            raise
        await asyncio.sleep(min(2 ** attempt, 60))
raise RuntimeError('still rate limited after retries')

Prevention

When it happens

Trigger: A tool body calling an upstream HTTP API that returns 429 (or raises an exception carrying status 429, detected via get_http_status_code) — the wrapper tool call then surfaces this ToolError.

Common situations: Tools proxying third-party APIs (OpenAI, GitHub, etc.) under burst load; shared API keys exhausting org-wide quotas; missing/incorrect API keys sometimes surfacing as 429 from gateways; retry loops with no backoff hammering a rate-limited endpoint.

Related errors


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