redis/redis-py · error · TokenRenewalErr

Requested token is expired

Error message

Requested token is expired

What it means

Raised as TokenRenewalErr from the sync _renew_token (redis/auth/token_manager.py:284) after acquire_token(force_refresh=True) returns a token whose is_expired() is True. The identity provider handed back a token that is already past its expiry, so renewal produced nothing usable. If an on_error listener is registered the error is routed there, otherwise it is re-raised.

Source

Thrown at redis/auth/token_manager.py:284

            - refresh_before
            - (datetime.now(timezone.utc).timestamp() * 1000)
        )

    def _renew_token(self, skip_initial: bool = False):
        """
        Task to renew token from identity provider.
        Schedules renewal tasks based on token TTL.
        """

        try:
            token_res = self.acquire_token(force_refresh=True)
            delay = self._calculate_renewal_delay(
                token_res.get_token().get_expires_at_ms(),
                token_res.get_token().get_received_at_ms(),
            )

            if token_res.get_token().is_expired():
                raise TokenRenewalErr("Requested token is expired")

            if self._listener.on_next is None:
                logger.warning(
                    "No registered callback for token renewal task. Renewal cancelled"
                )
                return

            if not skip_initial:
                try:
                    self._listener.on_next(token_res.get_token())
                except Exception as e:
                    raise TokenRenewalErr(e)

            if delay <= 0:
                return

            loop = asyncio.get_running_loop()
            self._next_timer = loop.call_later(delay, self._renew_token)

View on GitHub (pinned to da03cdc7e8)

Solutions

  1. Check for clock skew between the client and the identity provider; synchronize NTP.
  2. Inspect the token's exp vs current time to confirm the IdP is issuing valid-lifetime tokens.
  3. Register an on_error listener to handle renewal failures gracefully and trigger re-auth.
  4. Retry renewal once after a short delay in case the issue is transient.

Example fix

# before
# token_manager renews and IdP returns already-expired token -> TokenRenewalErr
# after
# register an on_error handler and verify IdP exp / clock sync
listener.on_error = lambda e: logging.error('renewal failed: %s', e)
Defensive patterns

Strategy: try-catch

Validate before calling

import time
token_exp = decoded_jwt.get('exp')
if token_exp is not None and token_exp * 1000 <= time.time() * 1000:
    logger.warning('IdP returned an already-expired token')

Type guard

def token_already_expired(token) -> bool:
    return token.is_expired()

Try / catch

from redis.auth.err import TokenRenewalErr
try:
    token_manager._renew_token()
except TokenRenewalErr as e:
    logger.error('sync renewal returned expired token: %s', e)
    reauthenticate()

Prevention

When it happens

Trigger: A scheduled/sync token renewal where the IdP's response token's exp is already in the past; significant clock skew between client and IdP; IdP misconfiguration issuing instantly-expiring tokens.

Common situations: Clock skew (client clock ahead of IdP); IdP bug returning expired tokens; long network delay between token issue and receipt; wrong exp units in the IdP response.

Related errors


AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04). Data as JSON: /data/errors/025f42546a7b61e1.json. Report an issue: GitHub.