Error message
Not enough segments
Also printed as
- jwt.exceptions.DecodeError: Not enough segments
PyJWT (Python) — jwt.exceptions.DecodeError
What it means
PyJWT could not split the input into `header.payload.signature`: it contains fewer than two dots. The string is not a compact JWS, so no key or algorithm was consulted. The value reaching `jwt.decode()` is something other than a JWT — or a JWT that lost its tail on the way.
Why it happens
An opaque access token, not a JWT
commonMany OAuth providers issue opaque access tokens (Google's `ya29.…`, GitHub's `gho_…`). They are meant to be validated by the provider through introspection or userinfo, not decoded. Only the OpenID Connect `id_token` is guaranteed to be a JWT.
The wrong variable was decoded
commonA session id, an API key, `str(None)` or the literal "undefined" from a front end. Logging `repr(token)[:40]` before decoding usually ends the search.
The token was cut off
occasionalA database column that is too short, a log line limit, or a manual copy that stopped early can remove the last segment and the dot before it.
How to fix it
- 1.
Check the shape before decoding
A compact JWS has exactly two dots. Reject anything else with 401 at the edge of your API, so malformed input never reaches the decoder.
python def bearer_token(headers: dict) -> str | None: scheme, _, token = headers.get("Authorization", "").partition(" ") if scheme.lower() != "bearer" or token.count(".") != 2: return None # not a compact JWS: answer 401 instead of decoding return token - 2.
Validate opaque tokens with the issuer
If the provider issues opaque access tokens, call its token introspection endpoint (RFC 7662), or configure the provider to issue JWT access tokens for your API (often by requesting an audience).
python import requests # Opaque tokens are validated by the authorization server (RFC 7662), not by decoding them. resp = requests.post( "https://issuer.example.com/oauth2/introspect", data={"token": token}, auth=(CLIENT_ID, CLIENT_SECRET), timeout=5, ) active = resp.json().get("active", False)