PrefectHQ/fastmcp · error · ValueError
Failed to convert JWK to PEM: {e}
Error message
Failed to convert JWK to PEM: {e} What it means
A matching JWK entry was found in the JWKS, but converting it to a PEM public key failed (`_jwk_to_pem` raised a jose error, TypeError, or ValueError). This means the JWK entry itself is malformed or of an unsupported type/curve.
Source
Thrown at fastmcp_slim/fastmcp/server/auth/cimd.py:700
if kid and key.get("kid") == kid:
matching_key = key
break
if not matching_key:
# If no kid match, try first key as fallback
if len(keys) == 1:
matching_key = keys[0]
self.logger.warning(
"No matching kid in JWKS, using single available key"
)
else:
raise ValueError(f"No matching key found for kid={kid} in JWKS")
# Convert JWK to PEM
try:
return _jwk_to_pem(matching_key)
except (JoseError, TypeError, ValueError) as e:
raise ValueError(f"Failed to convert JWK to PEM: {e}") from e
class CIMDClientManager:
"""Manages all CIMD client operations for OAuth proxy.
This class encapsulates:
- CIMD client detection
- Document fetching and validation
- Synthetic OAuth client creation
- Private key JWT assertion validation
This allows the OAuth proxy to delegate all CIMD-specific logic to a
single, focused manager class.
"""
def __init__(
self,
enable_cimd: bool = True,View on GitHub (pinned to 1f02114297)
Solutions
- Regenerate the JWK entry with a proper tool so base64url components are complete and correct (e.g. publish the RSA `n`/`e` from the actual signing key)
- Use a supported key type — RSA or an EC curve supported by the installed cryptography backend
- Ensure the JWKS entry is a public asymmetric key (not `kty: oct`), including public components
- Compare the JWKS entry against the issuer's canonical published JWKS and replace the malformed entry
Example fix
// before (truncated modulus)
{"kty": "RSA", "kid": "key-1", "n": "abc", "e": "AQAB"}
// after (full base64url modulus)
{"kty": "RSA", "kid": "key-1", "n": "0vx7agoebGcQS...full modulus...", "e": "AQAB"} Defensive patterns
Strategy: validation
Validate before calling
from jose import jwt as jose_jwt
from jose.exceptions import JOSEError
for k in jwks["keys"]:
try:
jose_jwt.algorithms.RSAAlgorithm.from_jwk(json.dumps(k))
except (JOSEError, ValueError) as e:
raise ValueError(f"Malformed JWK {k.get('kid')}: {e}") Type guard
def is_wellformed_rsa_jwk(k: dict) -> bool:
return k.get("kty") == "RSA" and bool(k.get("n")) and bool(k.get("e")) Try / catch
try:
key = extract_public_key(jwks, kid)
except ValueError as e:
if "Failed to convert JWK to PEM" in str(e):
logger.error("JWKS entry malformed; refetch/repair JWKS for kid=%s", kid)
raise Prevention
- Generate JWKS entries with a maintained tool (e.g. authlib, jose) rather than hand-writing base64url values
- Only publish public asymmetric keys (RSA/EC), never `kty: oct` symmetric keys in an assertion JWKS
- Validate the full JWKS round-trips to PEM at deployment/startup time
- Check that key components are complete un-padded base64url strings
When it happens
Trigger: The selected JWK has missing/invalid fields (e.g. bad `n`/`e` base64url for RSA, unsupported `kty` or `crv`, truncated key material), causing the python-jose conversion to fail while extracting the public key in `_extract_public_key_from_jwks`.
Common situations: Hand-authored JWKS with copy-paste-corrupted base64url values; unsupported key type (EC curve not supported by the crypto backend, OKP/Ed25519 keys); a JWK containing a private-only or symmetric (`kty: oct`) key where an RSA/EC public key is required.
Related errors
- CIMD jwks_uri failed SSRF validation: {e}
- JWKS document contains no keys
- No matching key found for kid={kid} in JWKS
- The device authorization request expired
- The device authorization request was denied
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/fcdd0741a32c1558.
Report an issue: GitHub.