PrefectHQ/fastmcp · error · ValueError

Invalid URL for configuration metadata

Error message

Invalid URL for configuration metadata: {attr}

What it means

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.

Solutions

  1. Fix the offending field in the provider's discovery document or your explicit config so it is a valid absolute http(s) URL
  2. Check for unexpanded env-var placeholders or whitespace in configuration
  3. If the provider metadata is wrong, override the endpoints with correct values in your proxy configuration

Example fix

// before
issuer = "${OIDC_ISSUER}"  # never expanded
// after
issuer = "https://idp.example.com"  # valid absolute URL
Defensive patterns

Strategy: validation

Validate before calling

from pydantic import AnyHttpUrl
for field in ("issuer", "authorization_endpoint", "token_endpoint", "jwks_uri"):
    AnyHttpUrl(meta[field])  # raises if not a valid absolute http(s) URL

Type guard

def is_valid_url(v: object) -> bool:
    try:
        AnyHttpUrl(v)  # type: ignore[arg-type]
        return True
    except Exception:
        return False

Try / catch

try:
    proxy = OIDCProxy(config_url=..., strict=True)
except ValueError as e:
    logger.error("invalid metadata URL: %s", e)
    raise SystemExit(1)

Prevention

When it happens

Trigger: 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.

Common situations: 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}'.

Related errors


AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29). Data as JSON: /api/errors/c009a663fb1c6ae6. Report an issue: GitHub.

Appendix: source

Thrown at fastmcp_slim/fastmcp/server/auth/oidc_proxy.py:138

        if not self.strict:
            return self

        def enforce(attr: str, is_url: bool = False) -> None:
            value = getattr(self, attr, None)
            if not value:
                message = f"Missing required configuration metadata: {attr}"
                logger.error(message)
                raise ValueError(message)

            if not is_url or isinstance(value, AnyHttpUrl):
                return

            try:
                AnyHttpUrl(value)
            except Exception as e:
                message = f"Invalid URL for configuration metadata: {attr}"
                logger.error(message)
                raise ValueError(message) from e

        enforce("issuer", True)
        enforce("authorization_endpoint", True)
        enforce("token_endpoint", True)
        enforce("jwks_uri", True)
        enforce("response_types_supported")
        enforce("subject_types_supported")
        enforce("id_token_signing_alg_values_supported")

        return self

    @classmethod
    def get_oidc_configuration(
        cls, config_url: AnyHttpUrl, *, strict: bool | None, timeout_seconds: int | None
    ) -> Self:
        """Get the OIDC configuration for the specified config URL.

        Args:

View on GitHub (pinned to 1f02114297)