{"record":{"id":"c009a663fb1c6ae6","repo":"PrefectHQ/fastmcp","slug":"invalid-url-for-configuration-metadata-attr","errorCode":null,"errorMessage":"Invalid URL for configuration metadata: {attr}","messagePattern":"Invalid URL for configuration metadata: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/server/auth/oidc_proxy.py","lineNumber":138,"sourceCode":"        if not self.strict:\n            return self\n\n        def enforce(attr: str, is_url: bool = False) -> None:\n            value = getattr(self, attr, None)\n            if not value:\n                message = f\"Missing required configuration metadata: {attr}\"\n                logger.error(message)\n                raise ValueError(message)\n\n            if not is_url or isinstance(value, AnyHttpUrl):\n                return\n\n            try:\n                AnyHttpUrl(value)\n            except Exception as e:\n                message = f\"Invalid URL for configuration metadata: {attr}\"\n                logger.error(message)\n                raise ValueError(message) from e\n\n        enforce(\"issuer\", True)\n        enforce(\"authorization_endpoint\", True)\n        enforce(\"token_endpoint\", True)\n        enforce(\"jwks_uri\", True)\n        enforce(\"response_types_supported\")\n        enforce(\"subject_types_supported\")\n        enforce(\"id_token_signing_alg_values_supported\")\n\n        return self\n\n    @classmethod\n    def get_oidc_configuration(\n        cls, config_url: AnyHttpUrl, *, strict: bool | None, timeout_seconds: int | None\n    ) -> Self:\n        \"\"\"Get the OIDC configuration for the specified config URL.\n\n        Args:","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/server/auth/oidc_proxy.py#L120-L156","documentation":"Strict-mode metadata validation found a required URL-typed field (issuer, authorization_endpoint, token_endpoint, or jwks_uri) that is populated but not a valid http(s) URL. AnyHttpUrl parsing fails and the original parse error is chained.","triggerScenarios":"Discovery metadata (or manually supplied config) contains a malformed or relative URL for one of the four enforced URL fields — e.g. issuer missing scheme, trailing whitespace, or an 'example' placeholder.","commonSituations":"Providers behind reverse proxies emitting http:// where https:// is expected or relative endpoint paths; copy-pasted config with typos; environment-substituted URLs left as empty templates like '${ISSUER}'.","solutions":["Fix the offending field in the provider's discovery document or your explicit config so it is a valid absolute http(s) URL","Check for unexpanded env-var placeholders or whitespace in configuration","If the provider metadata is wrong, override the endpoints with correct values in your proxy configuration"],"exampleFix":"// before\nissuer = \"${OIDC_ISSUER}\"  # never expanded\n// after\nissuer = \"https://idp.example.com\"  # valid absolute URL","handlingStrategy":"validation","validationCode":"from pydantic import AnyHttpUrl\nfor field in (\"issuer\", \"authorization_endpoint\", \"token_endpoint\", \"jwks_uri\"):\n    AnyHttpUrl(meta[field])  # raises if not a valid absolute http(s) URL","typeGuard":"def is_valid_url(v: object) -> bool:\n    try:\n        AnyHttpUrl(v)  # type: ignore[arg-type]\n        return True\n    except Exception:\n        return False","tryCatchPattern":"try:\n    proxy = OIDCProxy(config_url=..., strict=True)\nexcept ValueError as e:\n    logger.error(\"invalid metadata URL: %s\", e)\n    raise SystemExit(1)","preventionTips":["Check for unexpanded env placeholders (${VAR}) in URLs before deploy","Ensure URLs are absolute with https:// scheme and no stray whitespace","Override provider metadata manually when a reverse proxy emits malformed endpoint URLs"],"tags":["oidc","configuration","url-validation"],"backgroundTag":"invalid-metadata-url","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}