{"record":{"id":"9e66e3e8a4d2b54a","repo":"PrefectHQ/fastmcp","slug":"failed-to-resolve-reference-ref-str-e","errorCode":null,"errorMessage":"Failed to resolve reference '{ref_str}': {e}","messagePattern":"Failed to resolve reference '(.+?)': (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/utilities/openapi/parser.py","lineNumber":211,"sourceCode":"                    elif isinstance(target, dict):\n                        target = target.get(part)\n                    else:\n                        raise ValueError(\n                            f\"Cannot traverse part '{part}' in reference '{ref_str}'\"\n                        )\n\n                    if target is None:\n                        raise ValueError(\n                            f\"Reference part '{part}' not found in path '{ref_str}'\"\n                        )\n\n                # Handle nested references\n                if isinstance(target, self.reference_cls):\n                    return self._resolve_ref(target)\n\n                return target\n            except (AttributeError, KeyError, IndexError, TypeError, ValueError) as e:\n                raise ValueError(f\"Failed to resolve reference '{ref_str}': {e}\") from e\n\n        return item\n\n    def _extract_schema_as_dict(self, schema_obj: Any) -> JsonSchema:\n        \"\"\"Resolves a schema and returns it as a dictionary.\"\"\"\n        try:\n            resolved_schema = self._resolve_ref(schema_obj)\n\n            if isinstance(resolved_schema, self.schema_cls):\n                # Convert schema to dictionary\n                result = resolved_schema.model_dump(\n                    mode=\"json\", by_alias=True, exclude_none=True\n                )\n            elif isinstance(resolved_schema, dict):\n                result = resolved_schema\n            else:\n                logger.warning(\n                    f\"Expected Schema after resolving, got {type(resolved_schema)}. Returning empty dict.\"","sourceCodeStart":193,"sourceCodeEnd":229,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/utilities/openapi/parser.py#L193-L229","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (dangling ref)\n\"$ref\": \"#/components/schemas/PetRepsonse\"\n// after (matches an existing definition)\n\"$ref\": \"#/components/schemas/PetResponse\"","handlingStrategy":"validation","validationCode":"def ref_target_exists(spec: dict, ref: str) -> bool:\n    if not ref.startswith(\"#/\"):\n        return False\n    node = spec\n    for part in ref[2:].split(\"/\"):\n        part = part.replace(\"~1\", \"/\").replace(\"~0\", \"~\")\n        if isinstance(node, dict) and part in node:\n            node = node[part]\n        elif isinstance(node, list) and part.isdigit() and int(part) < len(node):\n            node = node[int(part)]\n        else:\n            return False\n    return True","typeGuard":"def is_local_ref(node: dict) -> bool:\n    ref = node.get(\"$ref\") if isinstance(node, dict) else None\n    return isinstance(ref, str) and ref.startswith(\"#/\")","tryCatchPattern":"try:\n    parsed = await parse(openapi_spec)\nexcept ValueError as e:\n    logger.error(\"Dangling $ref in spec: %s\", e.__cause__)\n    raise SpecValidationError(str(e)) from e","preventionTips":["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."],"tags":["openapi","json-ref","schema-resolution"],"backgroundTag":"dangling-json-ref","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}