PrefectHQ/fastmcp · error · CIMDValidationError
CIMD client_id mismatch: document says '{doc.client_id}' but
Error message
CIMD client_id mismatch: document says '{doc.client_id}' but was fetched from '{client_id_url}' What it means
The CIMD spec requires that the client_id field inside the metadata document exactly match the URL the document was fetched from (modulo trailing slash). fetch() compares them after rstrip('/') and raises CIMDValidationError on mismatch, preventing clients from claiming someone else's identity.
Source
Thrown at fastmcp_slim/fastmcp/server/auth/cimd.py:418
else:
self._remove_cache_entry(client_id_url)
return cached.doc
now = time.time()
policy = self._parse_cache_policy(response.headers, now)
try:
data = json.loads(response.content)
except json.JSONDecodeError as e:
raise CIMDValidationError(f"CIMD document is not valid JSON: {e}") from e
try:
doc = CIMDDocument.model_validate(data)
except Exception as e:
raise CIMDValidationError(f"Invalid CIMD document: {e}") from e
if str(doc.client_id).rstrip("/") != client_id_url.rstrip("/"):
raise CIMDValidationError(
f"CIMD client_id mismatch: document says '{doc.client_id}' "
f"but was fetched from '{client_id_url}'"
)
# Validate jwks_uri if present (SSRF check for JWKS endpoint)
if doc.jwks_uri:
jwks_uri_str = str(doc.jwks_uri)
try:
await validate_url(jwks_uri_str)
except SSRFError as e:
raise CIMDValidationError(
f"CIMD jwks_uri failed SSRF validation: {e}"
) from e
logger.info(
"CIMD document fetched and validated: %s (client_name=%s)",
client_id_url,
doc.client_name,View on GitHub (pinned to 1f02114297)
Solutions
- Update the client_id field inside the hosted JSON document to exactly equal the URL where it is hosted
- Check scheme, host, port, and path — all must match (only trailing '/' is ignored)
- If the document was moved, update the embedded client_id and point clients at the new URL
- Avoid serving the document from a URL that redirects; serve it directly at the canonical client_id URL
Example fix
// document hosted at https://app.example.com/client.json
// before
{"client_id": "https://staging.example.com/client.json", ...}
// after
{"client_id": "https://app.example.com/client.json", ...} Defensive patterns
Strategy: validation
Validate before calling
def client_id_matches(doc: dict, hosted_url: str) -> bool:
return str(doc.get("client_id", "")).rstrip("/") == hosted_url.rstrip("/") Try / catch
try:
doc = await fetcher.get_client(client_id)
except CIMDValidationError as e:
if "client_id mismatch" in str(e):
raise InvalidClientError("document client_id must equal hosting URL") from e
raise Prevention
- Generate the client_id field programmatically from the hosting URL
- Re-check the embedded client_id after any domain/hosting migration
- Avoid redirects between the canonical client_id URL and the content
When it happens
Trigger: A CIMD document whose 'client_id' value differs from client_id_url — e.g. document hosted at https://a.example.com/client.json declaring client_id 'https://b.example.com/client.json', or http vs https mismatch, or trailing-path differences.
Common situations: Document copied from a staging environment to production without updating the embedded client_id; hosting moved to a new domain; trailing-slash or scheme (http/https) discrepancies; documents served from a redirect where fetch URL differs from canonical URL.
Related errors
- CIMD redirect_uri must have a host: {uri!r}
- CIMD document is not valid JSON: {e}
- CIMD document must have jwks_uri or jwks for private_key_jwt
- Invalid client assertion: {e}
- CIMD documents cannot use shared-secret auth methods: {v}. U
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/4cc5426a79ac4c9e.
Report an issue: GitHub.