{"record":{"id":"ebfbfff048e41e90","repo":"PrefectHQ/fastmcp","slug":"reference-part-part-not-found-in-path-ref-st","errorCode":null,"errorMessage":"Reference part '{part}' not found in path '{ref_str}'","messagePattern":"Reference part '(.+?)' not found in path '(.+?)'","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/utilities/openapi/parser.py","lineNumber":201,"sourceCode":"                        elif target.model_extra and part in target.model_extra:\n                            target = target.model_extra[part]\n                        else:\n                            # Special handling for components\n                            if part == \"components\" and hasattr(target, \"components\"):\n                                target = target.components\n                            elif hasattr(target, part):  # Fallback check\n                                target = getattr(target, part, None)\n                            else:\n                                target = None  # Part not found\n                    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","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/utilities/openapi/parser.py#L183-L219","documentation":"This is the 'dead end' variant of reference resolution: _resolve_ref traversed a valid-looking '#/...' pointer but at some segment the lookup returned None, meaning that part does not exist in the document at that point. The parser raises ValueError naming the missing part and full ref. It signals a dangling or stale $ref — the path syntax is fine, but the target was never defined, was renamed, or was removed.","triggerScenarios":"$ref values like '#/components/schemas/User' when components/schemas contains no 'User' key (typo, case mismatch, or the definition was removed); refs kept after stripping shared components from a spec; two specs where one references components only present in the other.","commonSituations":"Editing specs by hand and renaming a schema without updating refs; build tooling that prunes unused components; merging API versions (v2 spec refs pointing at v1 components); copy-pasting refs between documents.","solutions":["Search the document for the missing key (`jq '.components.schemas | keys' spec.json`) and correct the ref's spelling/casing to match an existing key.","Ensure every $ref target exists after any preprocessing/pruning — run a $ref integrity checker or openapi-spec-validator on the final bundled document.","If components were intentionally removed, inline the definition at the ref site instead of keeping a dangling pointer.","Regenerate the spec from the source framework so refs and components are produced together.","Check for case-sensitivity mismatches ('User' vs 'user') and version drift between spec files."],"exampleFix":"// before\n$ref: '#/components/schemas/user'   # only 'User' exists\n\n// after\n$ref: '#/components/schemas/User'","handlingStrategy":"validation","validationCode":"import json\n\ndef dangling_refs(spec: dict) -> list[str]:\n    refs = walk_all_refs(spec)  # collect every $ref string\n    def exists(ref: str) -> bool:\n        node = spec\n        for part in ref[2:].split(\"/\"):\n            part = part.replace(\"~1\", \"/\").replace(\"~0\", \"~\")\n            if not isinstance(node, dict) or part not in node:\n                return False\n            node = node[part]\n        return True\n    return [r for r in refs if not exists(r)]\n\nbad = dangling_refs(spec)\nassert not bad, f\"Dangling refs: {bad}\"","typeGuard":"def ref_target_exists(spec: dict, ref: str) -> bool:\n    if not ref.startswith(\"#/\"):\n        return False\n    node: object = spec\n    for part in ref[2:].split(\"/\"):\n        if isinstance(node, dict) and part in node:\n            node = node[part]\n        else:\n            return False\n    return True","tryCatchPattern":"try:\n    routes = parse_openapi_to_http_routes(spec)\nexcept ValueError as e:\n    if \"not found in path\" in str(e):\n        logger.error(\"Dangling $ref: %s\", e)\n        raise SystemExit(\"Define the missing component or fix the ref\") from e\n    raise","preventionTips":["Run a dangling-ref check in CI after every spec edit or component prune.","Rename components via find-and-replace across all refs, never by editing one side.","Regenerate specs from source rather than maintaining refs by hand.","Run openapi-spec-validator; it reports unresolvable local refs."],"tags":["openapi","references","json-pointer"],"backgroundTag":"unresolved-openapi-ref","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}