redis/node-redis · error · Error

invalid sentinelClientOptions for Sentinel

Error message

invalid sentinelClientOptions for Sentinel

What it means

Symmetric to the nodeClientOptions guard: Sentinel derives the addresses of the sentinel-monitor processes from `rootNodes`/discovery, so a hard-coded `url` in `sentinelClientOptions` is meaningless and rejected. Only the sentinel-monitor client options are validated here (after the sentinel module is forced onto them).

Solutions

  1. Remove `url` from `sentinelClientOptions`; supply sentinel endpoints via `rootNodes`.
  2. Keep only auth/socket fields (e.g. `password`, TLS) in `sentinelClientOptions`.
  3. If you need a single sentinel endpoint, put it in `rootNodes: [{ host, port }]`.

Example fix

// before
new RedisSentinel({ name: 'mymaster', sentinelClientOptions: { url: 'redis://sentinel:26379' } }, id);
// after
new RedisSentinel({ name: 'mymaster', rootNodes: [{ host: 'sentinel', port: 26379 }], sentinelClientOptions: { password: 'sentinel-secret' } }, id);
Defensive patterns

Strategy: validation

Validate before calling

function assertSentinelOpts(opts: { sentinelClientOptions?: { url?: unknown } }) {
  if (opts.sentinelClientOptions && opts.sentinelClientOptions.url !== undefined) {
    throw new Error('sentinelClientOptions.url is forbidden for Sentinel; use rootNodes');
  }
}
assertSentinelOpts(opts);

Type guard

function hasNoSentinelUrl(opts: { sentinelClientOptions?: { url?: unknown } }): boolean {
  return opts.sentinelClientOptions?.url === undefined;
}

Try / catch

try { new RedisSentinel(opts, id); }
catch (e) {
  if (String(e).includes('invalid sentinelClientOptions')) {
    const { url, ...rest } = opts.sentinelClientOptions ?? {};
    opts = { ...opts, sentinelClientOptions: rest };
    new RedisSentinel(opts, id);
  } else throw e;
}

Prevention

When it happens

Trigger: Passing `sentinelClientOptions: { url: 'redis://...' }` to `new RedisSentinel(...)`. Throws synchronously in the constructor.

Common situations: Sharing one options object between nodeClientOptions and sentinelClientOptions where a url slipped in; copy-pasting a standalone client URL into the sentinel monitor config.

Related errors


AI-assisted analysis of redis/node-redis@90fd0652bc (2026-08-11). Data as JSON: /api/errors/fa533cced956d87a. Report an issue: GitHub.

Appendix: source

Thrown at packages/client/lib/sentinel/index.ts:885

    // a failover must be transparently re-preparable on the promoted master's connections.
    // (Sentinel-monitor clients use #sentinelClientOptions and never run HIMPORT.)
    this.#nodeClientOptions.himportRegistry = new FieldsetRegistry();

    if (options.clientSideCache) {
      if (options.clientSideCache instanceof PooledClientSideCacheProvider) {
        this.#clientSideCache = this.#nodeClientOptions.clientSideCache = options.clientSideCache;
      } else {
        const cscConfig = options.clientSideCache;
        this.#clientSideCache = this.#nodeClientOptions.clientSideCache = new BasicPooledClientSideCache(cscConfig);
//        this.#clientSideCache = this.#nodeClientOptions.clientSideCache = new PooledNoRedirectClientSideCache(cscConfig);
      }
    }

    this.#sentinelClientOptions = options.sentinelClientOptions ? Object.assign({} as RedisClientOptions<typeof RedisSentinelModule, F, S, RESP, TYPE_MAPPING, RedisTcpSocketOptions>, options.sentinelClientOptions) : {};
    this.#sentinelClientOptions.modules = RedisSentinelModule;

    if (this.#sentinelClientOptions.url !== undefined) {
      throw new Error("invalid sentinelClientOptions for Sentinel");
    }

    this.#masterClientQueue = new WaitQueue();
    for (let i = 0; i < this.#masterPoolSize; i++) {
      this.#masterClientQueue.push(i);
    }

    /* persistent object for life of sentinel object */
    this.#pubSubProxy = new PubSubProxy(
      this.#nodeClientOptions,
      err => this.emit('error', err)
    );
  }

  #createClient(
    node: RedisNode,
    clientOptions: AnyRedisClientOptions,
    reconnectStrategy?: false

View on GitHub (pinned to 90fd0652bc)