PrefectHQ/fastmcp · error · ValueError
trusted_issuers entries must be non-empty strings
Error message
trusted_issuers entries must be non-empty strings
What it means
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.
Source
Thrown at fastmcp_slim/fastmcp/server/auth/identity_assertion.py:149
)
access_token_expiry_seconds: int = Field(
default=300,
gt=0,
description=(
"Lifetime, in seconds, of the short-lived access token minted from an "
"ID-JAG. SEP-990 relies on the client re-exchanging a fresh assertion, so "
"this is intentionally short and no refresh token is issued."
),
)
@field_validator("trusted_issuers")
@classmethod
def _validate_trusted_issuers(cls, v: list[str]) -> list[str]:
if not v:
raise ValueError("identity_assertion.trusted_issuers must not be empty")
for issuer in v:
if not issuer or not issuer.strip():
raise ValueError("trusted_issuers entries must be non-empty strings")
return v
@field_validator("algorithm")
@classmethod
def _validate_algorithm(cls, v: str | None) -> str | None:
# Trusted issuers are verified via JWKS (public keys only), so the
# algorithm must be one of the asymmetric JWS algorithms JWTVerifier
# actually supports — HS* (shared-secret) has no JWKS equivalent, and
# anything else (EdDSA, or a typo like RS999) would otherwise surface
# as a 500 on the first exchange instead of a clean config error now.
if v is not None and v not in SUPPORTED_ASSERTION_ALGORITHMS:
supported = ", ".join(sorted(SUPPORTED_ASSERTION_ALGORITHMS))
raise ValueError(
f"Unsupported algorithm {v!r} for identity assertion: trusted "
f"issuers are verified via JWKS, so algorithm must be one of "
f"{supported}"
)
return vView on GitHub (pinned to 1f02114297)
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
Example fix
# before
TRUSTED_ISSUERS="https://a.com,,https://b.com" # -> ['', ''] entries
# after
issuers = [u.strip() for u in os.environ["TRUSTED_ISSUERS"].split(",") if u.strip()] Defensive patterns
Strategy: validation
Validate before calling
issuers = [u for u in raw_issuers if isinstance(u, str) and u.strip()] assert issuers == raw_issuers, "trusted_issuers contained blank entries"
Type guard
def all_issuers_nonempty(v: list) -> bool:
return all(isinstance(i, str) and i.strip() for i in v) Try / catch
try:
settings = IdentityAssertionSettings(trusted_issuers=raw_issuers)
except ValidationError as e:
logger.error("Blank trusted_issuers entry: %s", e)
raise SystemExit(1) Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- identity_assertion.trusted_issuers must not be empty
- At least one of 'tools', 'include_tags', or 'exclude_tags' i
- The API key is empty
- The Horizon API key is invalid
- Invalid URL: {url}
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/464f1475e1b99e68.
Report an issue: GitHub.