PrefectHQ/fastmcp · error · ValueError

CIMD redirect_uris must be non-empty strings

Error message

CIMD redirect_uris must be non-empty strings

What it means

A Pydantic ValueError from the same redirect_uris validator (fastmcp_slim/fastmcp/server/auth/cimd.py:148) raised when an individual entry in redirect_uris is None, an empty string, or whitespace-only. Each advertised redirect URI must be a non-empty string to serve as a usable callback target.

Source

Thrown at fastmcp_slim/fastmcp/server/auth/cimd.py:155

    def validate_auth_method(cls, v: str) -> str:
        """Ensure no shared-secret auth methods are used."""
        forbidden = {"client_secret_post", "client_secret_basic", "client_secret_jwt"}
        if v in forbidden:
            raise ValueError(
                f"CIMD documents cannot use shared-secret auth methods: {v}. "
                "Use 'none' or 'private_key_jwt' instead."
            )
        return v

    @field_validator("redirect_uris")
    @classmethod
    def validate_redirect_uris(cls, v: list[str]) -> list[str]:
        """Ensure redirect_uris is non-empty and each entry is a valid URI."""
        if not v:
            raise ValueError("CIMD documents must include at least one redirect_uri")
        for uri in v:
            if not uri or not uri.strip():
                raise ValueError("CIMD redirect_uris must be non-empty strings")
            parsed = urlparse(uri)
            if not parsed.scheme:
                raise ValueError(
                    f"CIMD redirect_uri must have a scheme (e.g. http:// or https://): {uri!r}"
                )
            if not parsed.netloc and not uri.startswith("urn:"):
                raise ValueError(f"CIMD redirect_uri must have a host: {uri!r}")
        return v


class CIMDValidationError(Exception):
    """Raised when CIMD document validation fails."""


class CIMDFetchError(Exception):
    """Raised when CIMD document fetching fails."""

View on GitHub (pinned to 1f02114297)

Solutions

  1. Remove empty/whitespace entries so redirect_uris contains only valid absolute URIs.
  2. If URIs come from environment variables, verify they are set and non-empty before generating the document.
  3. Filter and strip entries in the producing code: [u.strip() for u in uris if u and u.strip()].

Example fix

// before
"redirect_uris": ["https://client.example.com/cb", ""]
// after
"redirect_uris": ["https://client.example.com/cb"]
Defensive patterns

Strategy: validation

Validate before calling

uris = doc.get('redirect_uris') or []
for uri in uris:
    if not isinstance(uri, str) or not uri.strip():
        raise ValueError(f'redirect_uris entries must be non-empty strings, got {uri!r}')
doc['redirect_uris'] = [u.strip() for u in uris if u and u.strip()]

Type guard

def is_valid_redirect_entry(uri) -> bool:
    return isinstance(uri, str) and bool(uri.strip())

Try / catch

from pydantic import ValidationError
try:
    document = CIMDDocument.model_validate(raw_doc)
except ValidationError as e:
    logger.error('Bad redirect_uri entry: %s', e)
    raise HTTPException(400, 'invalid_client_metadata') from e

Prevention

When it happens

Trigger: A CIMD document's redirect_uris array contains "" or " " (or a null coerced in), e.g. ["https://client.example.com/cb", ""] — the list is non-empty so the empty-list check doesn't fire, but this entry fails the `not uri or not uri.strip()` check.

Common situations: A trailing empty string left by splitting a comma-separated URI list; hand-edited JSON with a placeholder never replaced; environment-interpolated URI variables that expanded to empty (e.g. ${CALLBACK_URL} unset).

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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