redis/redis-py · error · InvalidTokenSchemaErr

Unexpected token schema. Following fields are missing

Error message

Unexpected token schema. Following fields are missing: {missing_fields}

What it means

Raised as InvalidTokenSchemaErr inside JWToken._validate_token when the decoded JWT is missing one or more required fields. JWToken.REQUIRED_FIELDS is {'exp'}, so at minimum the token must contain an 'exp' (expiration) claim. The error message lists exactly which fields are missing. This guards against malformed or non-standard tokens before the token manager tries to compute TTL/renewal.

Solutions

  1. Inspect the token payload (jwt.decode without verification) and confirm it contains 'exp'.
  2. Have the identity provider include the 'exp' claim in issued tokens.
  3. If using a token format without 'exp', use a different Token implementation rather than JWToken.
  4. Re-acquire a fresh, complete token from the issuer.

Example fix

# before: token lacks 'exp'
token = JWToken("eyJ...payload_without_exp...")  # InvalidTokenSchemaErr
# after: issuer includes exp
token = JWToken("eyJ...payload_with_exp...")
Defensive patterns

Strategy: validation

Validate before calling

import jwt
payload = jwt.decode(value, options={"verify_signature": False})
if "exp" not in payload:
    raise ValueError("token missing required 'exp' claim")

Type guard

def has_required_claims(value: str, required={"exp"}) -> bool:
    import jwt
    payload = jwt.decode(value, options={"verify_signature": False})
    return required.issubset(payload.keys())

Try / catch

from redis.auth.err import InvalidTokenSchemaErr
try:
    token = JWToken(value)
except InvalidTokenSchemaErr as e:
    logger.error("rejecting malformed token: %s", e)
    raise

Prevention

When it happens

Trigger: Constructing JWToken with a token string whose decoded payload lacks the 'exp' claim (or any future field added to REQUIRED_FIELDS). Triggered during token_manager initialization or renewal when it wraps the acquired token in a JWToken.

Common situations: The identity provider issued a token without an expiration claim. The token was truncated or corrupted. A custom/legacy token format that omits 'exp'. Clock/encoding issues producing a payload PyJWT decoded but with unexpected keys.

Understand the failure class

Related errors


AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10). Data as JSON: /api/errors/dc8fa2d5792c9317. Report an issue: GitHub.

Appendix: source

Thrown at redis/auth/token.py:130

        )

    def try_get(self, key: str) -> str:
        return self._decoded.get(key)

    def get_value(self) -> str:
        return self._value

    def get_expires_at_ms(self) -> float:
        return float(self._decoded["exp"] * 1000)

    def get_received_at_ms(self) -> float:
        return datetime.now(timezone.utc).timestamp() * 1000

    def _validate_token(self):
        actual_fields = {x for x in self._decoded.keys()}

        if len(self.REQUIRED_FIELDS - actual_fields) != 0:
            raise InvalidTokenSchemaErr(self.REQUIRED_FIELDS - actual_fields)

View on GitHub (pinned to 6a6b581b48)