PrefectHQ/fastmcp · error · ValueError

CIMD redirect_uri must have a host: {uri!r}

Error message

CIMD redirect_uri must have a host: {uri!r}

What it means

The CIMD document's redirect_uris validator requires every redirect URI to parse into a scheme and a network location (host). A URI with a scheme but no host (e.g. 'https:///callback' or 'myapp://') is rejected because the OAuth server cannot meaningfully match or redirect to it. Only 'urn:' URIs are exempted from the host requirement per RFC 8252 conventions.

Source

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

            )
        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."""


@dataclass
class _CIMDCacheEntry:
    """Cached CIMD document and associated HTTP cache metadata."""

    doc: CIMDDocument
    etag: str | None
    last_modified: str | None

View on GitHub (pinned to 1f02114297)

Solutions

  1. Fix the redirect_uri in the hosted CIMD document to include a host, e.g. 'https://app.example.com/callback'
  2. For native apps using custom schemes, use a scheme+host form like 'com.example.app://oauth/callback' (or an exempted 'urn:ietf:wg:oauth:2.0:oob' style URI)
  3. Re-host the corrected document and ensure the client_id URL still matches, then retry

Example fix

// before (CIMD document JSON)
"redirect_uris": ["https:///callback"]
// after
"redirect_uris": ["https://app.example.com/callback"]
Defensive patterns

Strategy: validation

Validate before calling

from urllib.parse import urlparse
def valid_redirect_uri(uri: str) -> bool:
    p = urlparse(uri)
    return bool(p.scheme) and (bool(p.netloc) or uri.startswith("urn:"))
uris = doc.get("redirect_uris", [])
assert uris and all(valid_redirect_uri(u) for u in uris), "bad redirect_uris"

Type guard

def is_absolute_uri(u: object) -> bool:
    return isinstance(u, str) and bool(urlparse(u).netloc)

Try / catch

try:
    doc = CIMDDocument.model_validate(data)
except ValidationError as e:
    ...  # surface per-field messages for redirect_uris

Prevention

When it happens

Trigger: CIMDDocument.model_validate() on a document whose redirect_uris contains an entry like 'https:///callback', 'mailto:foo', or any scheme-qualified URI missing a host component; the validator runs inside CIMDFetcher.fetch() and CIMDClientManager flows that validate CIMD documents.

Common situations: Hand-authored CIMD JSON documents hosted by the client developer; custom-scheme mobile redirect URIs written without an authority (e.g. 'com.example.app:/oauth' instead of 'com.example.app://redirect'); copy-paste errors dropping the host portion of a URL.

Related errors


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