redis/redis-py · error · TokenRenewalErr
{e}
Error message
{e} What it means
Raised as TokenRenewalErr(e) wrapping whatever exception the user-supplied on_next callback threw during synchronous token renewal. _renew_token calls self._listener.on_next(token) to deliver the renewed token; if that callback raises, the error is re-raised as a TokenRenewalErr. The original exception e is preserved as the message/cause.
Solutions
- Inspect the wrapped exception e (the TokenRenewalErr cause) to find the real failure in on_next.
- Make the on_next callback defensive: catch and handle its own errors so renewal is not aborted.
- If on_error is registered, the manager routes it there instead of raising — register an on_error handler.
Example fix
# before
def on_next(token):
redis.auth(token.get_value()) # raises if connection closed
# after
def on_next(token):
try:
redis.auth(token.get_value())
except Exception:
logger.exception("failed to apply renewed token") Defensive patterns
Strategy: try-catch
Try / catch
def on_next(token):
try:
apply_token(token)
except Exception:
logger.exception("on_next failed; renewal will be aborted")
raise Prevention
- Make on_next callbacks defensive so transient apply failures do not kill renewal.
- Register on_error to route failures instead of propagating.
When it happens
Trigger: Registering an on_next listener on the token manager whose body raises (e.g. fails to persist the token, calls a failing Redis AUTH, or has a bug). The sync renewal path invokes it and wraps the failure in TokenRenewalErr.
Common situations: A callback that applies the new token via AUTH but the connection is closed. A callback with a bug or that hits a downstream service error. Persisting the token to disk/storage that is full or read-only.
Related errors
- Requested token is expired
- Bad query
- Connection closed by server.
- Connection closed by server.
- Connection closed by server.
AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10).
Data as JSON: /api/errors/e8a2c05f35b372fd.
Report an issue: GitHub.
Appendix: source
Thrown at redis/auth/token_manager.py:296
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)
logger.info(f"Next token renewal scheduled in {delay} seconds")
return token_res
except Exception as e:
if self._listener.on_error is None:
raise e
self._listener.on_error(e)
async def _renew_token_async(
self, skip_initial: bool = False, init_event: asyncio.Event = None
):
"""View on GitHub (pinned to 6a6b581b48)