{"record":{"id":"c3a69f162e46e589","repo":"PrefectHQ/fastmcp","slug":"cimd-redirect-uris-must-be-non-empty-strings","errorCode":null,"errorMessage":"CIMD redirect_uris must be non-empty strings","messagePattern":"CIMD redirect_uris must be non-empty strings","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/server/auth/cimd.py","lineNumber":155,"sourceCode":"    def validate_auth_method(cls, v: str) -> str:\n        \"\"\"Ensure no shared-secret auth methods are used.\"\"\"\n        forbidden = {\"client_secret_post\", \"client_secret_basic\", \"client_secret_jwt\"}\n        if v in forbidden:\n            raise ValueError(\n                f\"CIMD documents cannot use shared-secret auth methods: {v}. \"\n                \"Use 'none' or 'private_key_jwt' instead.\"\n            )\n        return v\n\n    @field_validator(\"redirect_uris\")\n    @classmethod\n    def validate_redirect_uris(cls, v: list[str]) -> list[str]:\n        \"\"\"Ensure redirect_uris is non-empty and each entry is a valid URI.\"\"\"\n        if not v:\n            raise ValueError(\"CIMD documents must include at least one redirect_uri\")\n        for uri in v:\n            if not uri or not uri.strip():\n                raise ValueError(\"CIMD redirect_uris must be non-empty strings\")\n            parsed = urlparse(uri)\n            if not parsed.scheme:\n                raise ValueError(\n                    f\"CIMD redirect_uri must have a scheme (e.g. http:// or https://): {uri!r}\"\n                )\n            if not parsed.netloc and not uri.startswith(\"urn:\"):\n                raise ValueError(f\"CIMD redirect_uri must have a host: {uri!r}\")\n        return v\n\n\nclass CIMDValidationError(Exception):\n    \"\"\"Raised when CIMD document validation fails.\"\"\"\n\n\nclass CIMDFetchError(Exception):\n    \"\"\"Raised when CIMD document fetching fails.\"\"\"\n\n","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/server/auth/cimd.py#L137-L173","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","solutions":["Remove empty/whitespace entries so redirect_uris contains only valid absolute URIs.","If URIs come from environment variables, verify they are set and non-empty before generating the document.","Filter and strip entries in the producing code: [u.strip() for u in uris if u and u.strip()]."],"exampleFix":"// before\n\"redirect_uris\": [\"https://client.example.com/cb\", \"\"]\n// after\n\"redirect_uris\": [\"https://client.example.com/cb\"]","handlingStrategy":"validation","validationCode":"uris = doc.get('redirect_uris') or []\nfor uri in uris:\n    if not isinstance(uri, str) or not uri.strip():\n        raise ValueError(f'redirect_uris entries must be non-empty strings, got {uri!r}')\ndoc['redirect_uris'] = [u.strip() for u in uris if u and u.strip()]","typeGuard":"def is_valid_redirect_entry(uri) -> bool:\n    return isinstance(uri, str) and bool(uri.strip())","tryCatchPattern":"from pydantic import ValidationError\ntry:\n    document = CIMDDocument.model_validate(raw_doc)\nexcept ValidationError as e:\n    logger.error('Bad redirect_uri entry: %s', e)\n    raise HTTPException(400, 'invalid_client_metadata') from e","preventionTips":["Filter blank entries after building redirect_uris from comma-separated or env-var sources.","Verify interpolated environment variables (e.g. CALLBACK_URL) are set before generating the document.","Strip whitespace when serializing URI lists into JSON."],"tags":["pydantic","cimd","validation","redirect-uri"],"backgroundTag":"schema-validation-failed","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}