PrefectHQ/fastmcp · error · ValueError

Invalid OpenAPI specification: {e}

Error message

Invalid OpenAPI specification: {e}

What it means

OpenAPIProvider.__init__ builds an openapi-core SchemaPath spec and RequestDirector from the supplied spec dict; if that library rejects the document, the exception is logged and re-raised as ValueError('Invalid OpenAPI specification: ...').

Source

Thrown at fastmcp_slim/fastmcp/server/providers/openapi/provider.py:149

        self._used_names: dict[str, Counter[str]] = {
            "tool": Counter(),
            "resource": Counter(),
            "resource_template": Counter(),
            "prompt": Counter(),
        }

        # Pre-created component storage
        self._tools: dict[str, OpenAPITool] = {}
        self._resources: dict[str, OpenAPIResource] = {}
        self._templates: dict[str, OpenAPIResourceTemplate] = {}

        # Create openapi-core Spec and RequestDirector
        try:
            self._spec = SchemaPath.from_dict(cast(Any, openapi_spec))
            self._director = RequestDirector(self._spec)
        except Exception as e:
            logger.exception("Failed to initialize RequestDirector")
            raise ValueError(f"Invalid OpenAPI specification: {e}") from e

        http_routes = parse_openapi_to_http_routes(openapi_spec)

        # Process routes
        route_maps = (route_maps or []) + DEFAULT_ROUTE_MAPPINGS
        for route in http_routes:
            route_map = _determine_route_type(route, route_maps)
            route_type = route_map.mcp_type

            if route_map_fn is not None:
                try:
                    result = route_map_fn(route, route_type)
                    if result is not None:
                        route_type = result
                        logger.debug(
                            f"Route {route.method} {route.path} mapping customized: "
                            f"type={route_type.name}"
                        )

View on GitHub (pinned to 1f02114297)

Solutions

  1. Validate the spec with a linter (e.g. openapi-spec-validator or Swagger Editor)
  2. Ensure spec['openapi'] is 3.x and 'paths' exists
  3. Load the file correctly (yaml.safe_load / json.load) and pass the parsed dict
  4. Read the chained message to find the offending schema path

Example fix

// before
spec = {'swagger': '2.0', 'paths': {}}
provider = FastMCPProvider(spec)
// after
spec = {'openapi': '3.1.0', 'info': {'title': 'api', 'version': '1.0'}, 'paths': {...}}
provider = FastMCPProvider(spec)
Defensive patterns

Strategy: validation

Validate before calling

from openapi_spec_validator import validate
def assert_valid_spec(spec: dict) -> None:
    validate(spec)
assert isinstance(spec, dict) and 'paths' in spec

Type guard

def is_valid_spec(spec: object) -> bool:
    return (
        isinstance(spec, dict)
        and isinstance(spec.get('openapi'), str)
        and spec['openapi'].startswith('3.')
        and isinstance(spec.get('paths'), dict)
    )

Try / catch

try:
    provider = FastMCPProvider(spec)
except ValueError as e:
    if str(e).startswith('Invalid OpenAPI specification'):
        log.error('spec rejected: %s', e.__cause__)
        raise
    raise

Prevention

When it happens

Trigger: Passing a dict to OpenAPIProvider/FastMCPProvider that is not a valid OpenAPI document (openapi-core validation fails): wrong version field, missing paths, malformed schema objects.

Common situations: Passing a Swagger 2.0 doc instead of OpenAPI 3.x, YAML loaded into the wrong structure, truncated JSON, hand-edited specs with schema typos.

Related errors


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