{"record":{"id":"464f1475e1b99e68","repo":"PrefectHQ/fastmcp","slug":"trusted-issuers-entries-must-be-non-empty-strings","errorCode":null,"errorMessage":"trusted_issuers entries must be non-empty strings","messagePattern":"trusted_issuers entries must be non-empty strings","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/server/auth/identity_assertion.py","lineNumber":149,"sourceCode":"    )\n    access_token_expiry_seconds: int = Field(\n        default=300,\n        gt=0,\n        description=(\n            \"Lifetime, in seconds, of the short-lived access token minted from an \"\n            \"ID-JAG. SEP-990 relies on the client re-exchanging a fresh assertion, so \"\n            \"this is intentionally short and no refresh token is issued.\"\n        ),\n    )\n\n    @field_validator(\"trusted_issuers\")\n    @classmethod\n    def _validate_trusted_issuers(cls, v: list[str]) -> list[str]:\n        if not v:\n            raise ValueError(\"identity_assertion.trusted_issuers must not be empty\")\n        for issuer in v:\n            if not issuer or not issuer.strip():\n                raise ValueError(\"trusted_issuers entries must be non-empty strings\")\n        return v\n\n    @field_validator(\"algorithm\")\n    @classmethod\n    def _validate_algorithm(cls, v: str | None) -> str | None:\n        # Trusted issuers are verified via JWKS (public keys only), so the\n        # algorithm must be one of the asymmetric JWS algorithms JWTVerifier\n        # actually supports — HS* (shared-secret) has no JWKS equivalent, and\n        # anything else (EdDSA, or a typo like RS999) would otherwise surface\n        # as a 500 on the first exchange instead of a clean config error now.\n        if v is not None and v not in SUPPORTED_ASSERTION_ALGORITHMS:\n            supported = \", \".join(sorted(SUPPORTED_ASSERTION_ALGORITHMS))\n            raise ValueError(\n                f\"Unsupported algorithm {v!r} for identity assertion: trusted \"\n                f\"issuers are verified via JWKS, so algorithm must be one of \"\n                f\"{supported}\"\n            )\n        return v","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/server/auth/identity_assertion.py#L131-L167","documentation":"Each entry in `trusted_issuers` must be a non-empty, non-whitespace string. The pydantic `field_validator` `_validate_trusted_issuers` rejects any empty or blank issuer at settings load time, since a blank issuer could never match an assertion's `iss` claim.","triggerScenarios":"A `trusted_issuers` list containing `\"\"`, `\"   \"`, or None-ish entries — e.g. trailing commas in a comma-separated env var producing empty strings, or `\"issuers\".split(\",\")` on a malformed value.","commonSituations":"Env var like `TRUSTED_ISSUERS=\"https://a.com,,https://b.com\"` producing an empty element; YAML/JSON config with empty string values; template substitution that left a placeholder empty.","solutions":["Remove the empty/blank entries so every list element is a full issuer URL","Fix the env-var splitting/parsing that introduced empty strings (filter falsy values)","Correct the config file to remove empty-string issuers"],"exampleFix":"# before\nTRUSTED_ISSUERS=\"https://a.com,,https://b.com\"  # -> ['', ''] entries\n# after\nissuers = [u.strip() for u in os.environ[\"TRUSTED_ISSUERS\"].split(\",\") if u.strip()]","handlingStrategy":"validation","validationCode":"issuers = [u for u in raw_issuers if isinstance(u, str) and u.strip()]\nassert issuers == raw_issuers, \"trusted_issuers contained blank entries\"","typeGuard":"def all_issuers_nonempty(v: list) -> bool:\n    return all(isinstance(i, str) and i.strip() for i in v)","tryCatchPattern":"try:\n    settings = IdentityAssertionSettings(trusted_issuers=raw_issuers)\nexcept ValidationError as e:\n    logger.error(\"Blank trusted_issuers entry: %s\", e)\n    raise SystemExit(1)","preventionTips":["Strip and filter entries when splitting comma-separated issuer env vars","Avoid trailing commas in hand-edited config lists","Lint config files for empty-string list values","Validate the parsed list matches the intended issuers before constructing settings"],"tags":["config","pydantic","validation","identity-assertion"],"backgroundTag":"empty-required-config-list","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}