PrefectHQ/fastmcp · error · ValueError

Invalid JWT format (expected 3 parts)

Error message

Invalid JWT format (expected 3 parts)

What it means

decode_jwt_header/decode_jwt_payload expect a JWT with exactly three dot-separated parts (header.payload.signature). Tokens that are opaque strings, access tokens in other formats, or truncated JWTs fail this check with a ValueError.

Source

Thrown at fastmcp_slim/fastmcp/utilities/auth.py:25

from typing import Any


def _decode_jwt_part(token: str, part_index: int) -> dict[str, Any]:
    """Decode a JWT part (header or payload) without signature verification.

    Args:
        token: JWT token string (header.payload.signature)
        part_index: 0 for header, 1 for payload

    Returns:
        Decoded part as a dictionary

    Raises:
        ValueError: If token is not a valid JWT format
    """
    parts = token.split(".")
    if len(parts) != 3:
        raise ValueError("Invalid JWT format (expected 3 parts)")

    part_b64 = parts[part_index]
    part_b64 += "=" * (-len(part_b64) % 4)  # Add padding
    return json.loads(base64.urlsafe_b64decode(part_b64))


def decode_jwt_header(token: str) -> dict[str, Any]:
    """Decode JWT header without signature verification.

    Useful for extracting the key ID (kid) for JWKS lookup.

    Args:
        token: JWT token string (header.payload.signature)

    Returns:
        Decoded header as a dictionary

    Raises:

View on GitHub (pinned to 1f02114297)

Solutions

  1. Verify the token is a JWT (two dots, base64url segments) before decoding
  2. Decode the ID token instead of the access token when using OAuth providers
  3. Check provider settings to ensure JWTs are being issued (RS256/HS256 signed tokens)

Example fix

// before
header = decode_jwt_header(access_token)

// after
if access_token.count(".") == 3 - 1:
    header = decode_jwt_header(access_token)
Defensive patterns

Strategy: validation

Validate before calling

def looks_like_jwt(token: str) -> bool:
    parts = token.split(".")
    return len(parts) == 3 and all(parts)

Type guard

def is_jwt(token: object) -> bool:
    return isinstance(token, str) and token.count(".") == 2

Try / catch

try:
    claims = decode_jwt_payload(token)
except ValueError as e:
    if "Invalid JWT format" in str(e):
        # token is opaque or truncated; fetch/verify the real JWT
        ...
    else:
        raise

Prevention

When it happens

Trigger: Passing a non-JWT token (e.g. an OAuth opaque access token or API key) to decode_jwt_header or decode_jwt_payload, or a JWT missing its signature part.

Common situations: Misconfiguring auth so an opaque provider token is treated as a JWT; copying a token partially; using ID-token decoding helpers on access tokens from providers like Auth0 or Google that are not JWTs.

Related errors


AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29). Data as JSON: /api/errors/944ed0cb2adbc8c4. Report an issue: GitHub.