PrefectHQ/fastmcp · error · ValueError

Failed to resolve reference '{ref_str}': {e}

Error message

Failed to resolve reference '{ref_str}': {e}

What it means

FastMCP's OpenAPI parser failed to resolve a JSON `$ref` pointer to a location in the OpenAPI document. `_resolve_ref` walks the document by splitting the `#/...` path and indexing into nested dicts/lists; if any hop is missing or has an unexpected type, the original exception (AttributeError, KeyError, IndexError, TypeError, ValueError) is re-raised as this ValueError with the ref string and underlying cause.

Source

Thrown at fastmcp_slim/fastmcp/utilities/openapi/parser.py:211

                    elif isinstance(target, dict):
                        target = target.get(part)
                    else:
                        raise ValueError(
                            f"Cannot traverse part '{part}' in reference '{ref_str}'"
                        )

                    if target is None:
                        raise ValueError(
                            f"Reference part '{part}' not found in path '{ref_str}'"
                        )

                # Handle nested references
                if isinstance(target, self.reference_cls):
                    return self._resolve_ref(target)

                return target
            except (AttributeError, KeyError, IndexError, TypeError, ValueError) as e:
                raise ValueError(f"Failed to resolve reference '{ref_str}': {e}") from e

        return item

    def _extract_schema_as_dict(self, schema_obj: Any) -> JsonSchema:
        """Resolves a schema and returns it as a dictionary."""
        try:
            resolved_schema = self._resolve_ref(schema_obj)

            if isinstance(resolved_schema, self.schema_cls):
                # Convert schema to dictionary
                result = resolved_schema.model_dump(
                    mode="json", by_alias=True, exclude_none=True
                )
            elif isinstance(resolved_schema, dict):
                result = resolved_schema
            else:
                logger.warning(
                    f"Expected Schema after resolving, got {type(resolved_schema)}. Returning empty dict."

View on GitHub (pinned to 1f02114297)

Solutions

  1. Open the spec at the location holding the offending `$ref` and make sure the referenced JSON pointer path exists verbatim (JSON pointers are case- and slash-sensitive).
  2. Regenerate the OpenAPI document from its source so definitions and refs stay in sync.
  3. Run a spec linter (e.g. spectral, openapi-spec-validator) before feeding the document to FastMCP to catch dangling refs.
  4. Read the chained cause (`raise ... from e`) — the KeyError/IndexError names exactly which path hop failed.

Example fix

// before (dangling ref)
"$ref": "#/components/schemas/PetRepsonse"
// after (matches an existing definition)
"$ref": "#/components/schemas/PetResponse"
Defensive patterns

Strategy: validation

Validate before calling

def ref_target_exists(spec: dict, ref: str) -> bool:
    if not ref.startswith("#/"):
        return False
    node = spec
    for part in ref[2:].split("/"):
        part = part.replace("~1", "/").replace("~0", "~")
        if isinstance(node, dict) and part in node:
            node = node[part]
        elif isinstance(node, list) and part.isdigit() and int(part) < len(node):
            node = node[int(part)]
        else:
            return False
    return True

Type guard

def is_local_ref(node: dict) -> bool:
    ref = node.get("$ref") if isinstance(node, dict) else None
    return isinstance(ref, str) and ref.startswith("#/")

Try / catch

try:
    parsed = await parse(openapi_spec)
except ValueError as e:
    logger.error("Dangling $ref in spec: %s", e.__cause__)
    raise SpecValidationError(str(e)) from e

Prevention

When it happens

Trigger: Parsing an OpenAPI spec whose schema/parameter/requestBody/response contains a `$ref` like `#/components/schemas/Pet` where the target path does not exist (e.g. `components` or `schemas` key absent, typo'd schema name), or where an intermediate node is a scalar instead of a dict, or a non-local ref was not caught earlier by other checks.

Common situations: Specs generated by tools that emit dangling refs (e.g. codegen from a model that renamed a schema), hand-edited specs with typos in ref names, partial documents produced by filtering/diffing tools that removed definitions but kept references, or specs using non-standard ref targets.

Related errors


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