PrefectHQ/fastmcp · error · ValueError

HTTP error {response.status_code}: {response.reason_phrase}

Error message

HTTP error {response.status_code}: {response.reason_phrase} - {error_data}

What it means

_raise_for_status in the OpenAPI provider converts non-2xx HTTP responses from the upstream API into a ValueError: "HTTP error {status}: {reason} - {body}". The message includes the parsed JSON error body (or raw text if the body is not JSON) so the developer can see exactly what the remote API rejected. It is raised from OpenAPI component run/read paths when the remote server returns an error.

Source

Thrown at fastmcp_slim/fastmcp/server/providers/openapi/components.py:74

logger = get_logger(__name__)

# Default MIME type when no response content type can be inferred
_DEFAULT_MIME_TYPE = "application/json"


def _raise_for_status(response: httpx2.Response) -> None:
    """Raise an OpenAPI-formatted error without relying on client exception types."""
    if 200 <= response.status_code < 300:
        return

    error_message = f"HTTP error {response.status_code}: {response.reason_phrase}"
    try:
        error_data = response.json()
        error_message += f" - {error_data}"
    except (json.JSONDecodeError, ValueError):
        if response.text:
            error_message += f" - {response.text}"
    raise ValueError(error_message)


async def _send_request(
    client: httpx2.AsyncClient,
    request: httpx2.Request,
) -> httpx2.Response:
    """Send a request while preserving transitional legacy-client errors."""
    try:
        return await client.send(request)
    except Exception as exc:
        if is_timeout_error(exc):
            raise ValueError(f"HTTP request timed out ({type(exc).__name__})") from exc
        if is_request_error(exc):
            raise ValueError(f"Request error ({type(exc).__name__}): {exc!s}") from exc
        raise


def _extract_mime_type_from_route(route: HTTPRoute) -> str:

View on GitHub (pinned to 1f02114297)

Solutions

  1. Read the appended error_data in the message — it usually states the upstream cause (invalid key, missing field, etc.)
  2. Verify and refresh the API credentials/config used by the OpenAPI provider
  3. Check that tool call arguments satisfy the operation's required parameters and types
  4. Confirm the base_url/server URL in the OpenAPI spec config is correct and reachable
  5. Retry with backoff on transient 429/5xx responses

Example fix

// before
result = await tool.run({"city": city})  # ValueError: HTTP error 401: Unauthorized - {...}
// after
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}
provider = OpenAPIProvider(openapi_spec=spec, client=client_with_headers(headers))
# then retry the call once credentials are fixed
Defensive patterns

Strategy: try-catch

Validate before calling

resp = await client.get(f"{base_url}/health")
if resp.status_code != 200:
    raise RuntimeError(f"upstream API unhealthy: {resp.status_code}")

Type guard

def is_retryable_status(status_code: int) -> bool:
    return status_code == 429 or status_code >= 500

Try / catch

try:
    result = await tool.run(args)
except ValueError as e:
    if "HTTP error 429" in str(e) or "HTTP error 5" in str(e):
        await asyncio.sleep(backoff)
        result = await tool.run(args)
    else:
        logger.error(f"upstream rejected request: {e}")
        raise

Prevention

When it happens

Trigger: Calling a tool/resource backed by an OpenAPI operation when the upstream HTTP API returns 4xx/5xx: bad or expired auth credentials, malformed request parameters generated from the tool call arguments, a wrong base_url in the OpenAPI config, rate limiting (429), or the downstream service being down (5xx).

Common situations: Expired API keys after rotation; calling tools whose required parameters were omitted or sent with wrong types; pointing fastmcp at a staging URL that no longer exists (404); gateway/proxy errors (502/503); the response body revealing auth or validation details from the upstream service.

Related errors


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