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

  1. Guard the call with manager.isRunning() first.
  2. Ensure start() has resolved before scheduling any manual refresh.
  3. 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

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


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)