redis/node-redis · error · Error
TokenManager is not running, but refresh was called
Error message
TokenManager is not running, but refresh was called
What it means
TokenManager.refresh() requires the manager to be running (listener set by start()). Calling refresh before start() or after stop() throws. The guard prevents operating on a manager with no listener to receive the new token.
Solutions
- Guard the call with manager.isRunning() first.
- Ensure start() has resolved before scheduling any manual refresh.
- Cancel timers that drive refresh before calling stop().
Example fix
// before
manager.refresh();
// after
if (manager.isRunning()) {
await manager.refresh();
} Defensive patterns
Strategy: validation
Validate before calling
if (manager.isRunning()) {
await manager.refresh();
} else {
// start it first, or skip
} Prevention
- Always pair manual refresh calls with an isRunning() check.
- Cancel timers driving refresh before calling stop().
- Treat start()/stop() as the lifecycle boundary; do not call refresh across it.
When it happens
Trigger: Calling manager.refresh() before start(listener) has been invoked; after stop() has been called; or after the manager auto-stopped following a fatal non-retryable IDP error.
Common situations: A setInterval that calls refresh outliving the manager; teardown ordering where refresh fires after stop; test cleanup racing a scheduled refresh; calling refresh from application code without checking lifecycle.
Related errors
- expirationRefreshRatio must be greater or equal to 0
- expirationRefreshRatio must be less than or equal to 1
- TokenManager is not running, but a new token was received
- TokenManager is not running but received an error
- All statistics values must be non-negative
AI-assisted analysis of redis/node-redis@90fd0652bc (2026-08-11).
Data as JSON: /api/errors/b85993fb596a6e0a.
Report an issue: GitHub.
Appendix: source
Thrown at packages/client/lib/authx/token-manager.ts:216
if (this.retryAttempt >= maxAttempts) {
return false;
}
if (isRetryable) {
return isRetryable(error, this.retryAttempt);
}
return false;
}
public isRunning(): boolean {
return this.listener !== null;
}
private async refresh(): Promise<void> {
if (!this.listener) {
throw new Error('TokenManager is not running, but refresh was called');
}
try {
await this.identityProvider.requestToken().then(this.handleNewToken);
this.retryAttempt = 0;
} catch (error) {
if (this.shouldRetry(error)) {
this.retryAttempt++;
const retryDelay = this.calculateRetryDelay();
this.notifyError(`Token refresh failed (attempt ${this.retryAttempt}), retrying in ${retryDelay}ms: ${error}`, true)
this.scheduleNextRefresh(retryDelay);
} else {
this.notifyError(error, false);
this.stop();
}
}
}View on GitHub (pinned to 90fd0652bc)