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
- 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).
- Regenerate the OpenAPI document from its source so definitions and refs stay in sync.
- Run a spec linter (e.g. spectral, openapi-spec-validator) before feeding the document to FastMCP to catch dangling refs.
- 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
- Lint specs with openapi-spec-validator or spectral before parsing.
- Never hand-edit $ref strings; regenerate or use tooling that keeps refs in sync.
- Bundle multi-file specs into one document before ingestion.
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
- HTTP error {response.status_code}: {response.reason_phrase}
- HTTP request timed out ({type(exc).__name__})
- Request error ({type(exc).__name__}): {exc!s}
- Error building request for {self._route.method.upper()} {sel
- Invalid OpenAPI specification: {e}
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/9e66e3e8a4d2b54a.
Report an issue: GitHub.