{"record":{"id":"7981aa99b1c97c33","repo":"PrefectHQ/fastmcp","slug":"external-or-non-local-reference-not-supported-re","errorCode":null,"errorMessage":"External or non-local reference not supported: {ref_str}","messagePattern":"External or non-local reference not supported: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/utilities/openapi/parser.py","lineNumber":169,"sourceCode":"            \"query\": \"query\",\n            \"header\": \"header\",\n            \"cookie\": \"cookie\",\n        }\n        if location := locations.get(param_in):\n            return location\n        logger.warning(f\"Unknown parameter location: {param_in}, defaulting to 'query'\")\n        return \"query\"\n\n    def _resolve_ref(self, item: Any) -> Any:\n        \"\"\"Resolves a reference to its target definition.\"\"\"\n        if isinstance(item, self.reference_cls):\n            ref_str = item.ref\n            # Ensure ref_str is a string before calling startswith()\n            if not isinstance(ref_str, str):\n                return item\n            try:\n                if not ref_str.startswith(\"#/\"):\n                    raise ValueError(\n                        f\"External or non-local reference not supported: {ref_str}\"\n                    )\n\n                parts = ref_str.strip(\"#/\").split(\"/\")\n                target = self.openapi\n\n                for part in parts:\n                    if part.isdigit() and isinstance(target, list):\n                        target = target[int(part)]\n                    elif isinstance(target, BaseModel):\n                        # Check class fields first, then model_extra\n                        if part in target.__class__.model_fields:\n                            target = getattr(target, part, None)\n                        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\"):","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/utilities/openapi/parser.py#L151-L187","documentation":"OpenAPIParser._resolve_ref only supports local JSON-pointer references that begin with '#/' (references within the same document). When a component's $ref points anywhere else — another file, an absolute URL, or any non-local string — the parser raises ValueError because cross-document resolution is not implemented. If the ref is not a string at all, the item is returned unresolved instead (no error).","triggerScenarios":"Parsing a spec whose schemas/parameters/responses contain $ref values like 'https://api.example.com/schemas/User.json', 'common.yaml#/components/schemas/X', or './types.json#/Foo' while running _extract_schema_as_dict, _extract_parameters, _extract_request_body, _extract_responses, or parse.","commonSituations":"Specs split across multiple files by a bundler that wasn't run (source refs left in); vendor-published specs referencing external schema URLs; manually edited specs with copied external refs; codegen output using relative file refs.","solutions":["Bundle the spec into a single self-contained document before parsing: `npx @redocly/cli bundle spec.yaml -o bundled.json` (or swagger-cli bundle) so all refs become '#/components/...'.","Inline external schemas manually: copy the referenced definitions into components/schemas and rewrite the $ref to '#/components/schemas/Name'.","If the external ref points to a stable URL, pre-fetch it and merge it into your spec at load time with a small script before calling the parser.","Regenerate the spec from the source (e.g. FastAPI) ensuring a single-file export without external refs."],"exampleFix":"// before (in spec.yaml)\n$ref: 'https://api.example.com/schemas/User.json'\n\n// after\n$ref: '#/components/schemas/User'  # definition inlined into the same document","handlingStrategy":"validation","validationCode":"import json\n\ndef find_external_refs(node, out=None):\n    out = [] if out is None else out\n    if isinstance(node, dict):\n        ref = node.get(\"$ref\")\n        if isinstance(ref, str) and not ref.startswith(\"#/\"):\n            out.append(ref)\n        for v in node.values():\n            find_external_refs(v, out)\n    elif isinstance(node, list):\n        for v in node:\n            find_external_refs(v, out)\n    return out\n\nexternal = find_external_refs(spec)\nassert not external, f\"Bundle first, external refs: {external}\"","typeGuard":"def is_local_ref(ref: object) -> bool:\n    return isinstance(ref, str) and ref.startswith(\"#/\")","tryCatchPattern":"try:\n    routes = parse_openapi_to_http_routes(spec)\nexcept ValueError as e:\n    if \"External or non-local reference\" in str(e):\n        raise SystemExit(\"Bundle the spec (e.g. redocly bundle) and retry\") from e\n    raise","preventionTips":["Always bundle multi-file specs before shipping them to parsers.","Run a ref scan (all $ref start with '#/') as a CI check.","Avoid tools that emit URL or file-relative refs in exports.","Keep a single self-contained spec artifact as the source of truth."],"tags":["openapi","references","unsupported"],"backgroundTag":"unresolved-openapi-ref","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}