redis/node-redis · error · Error

invalid sentinelClientOptions for Sentinel

Error message

invalid sentinelClientOptions for Sentinel

What it means

Thrown in the RedisSentinelInternal constructor when options.sentinelClientOptions contains a `url` field. The Sentinel topology discovers master/replica host:port pairs at runtime and builds connections from them, so a hard-coded `url` on the sentinel-monitor client would be contradictory and ignored. The constructor explicitly rejects this misconfiguration (sentinel/index.ts:884) the same way it rejects `url` on nodeClientOptions (sentinel/index.ts:863).

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 bb5beb5657)

Solutions

  1. Remove the `url` field from sentinelClientOptions — the Sentinel client supplies host/port per discovered node.
  2. Move connection details into sentinelClientOptions.socket and sentinelClientOptions.{username,password} instead of a URL.
  3. If you need URL-style config for the *data* nodes, put it on nodeClientOptions (also url-free) or use socket.host/port plus credentials.
  4. Lint your config builder so sentinelClientOptions is always constructed object-literal, never from parseURL().

Example fix

// before
const sentinel = factory.createClient({
  sentinelClientOptions: { url: 'rediss://sentinel:26379' }
});
// after
const sentinel = factory.createClient({
  sentinelClientOptions: {
    socket: { tls: true, reconnectStrategy: 1000 },
    username: 'sentinelUser', password: process.env.SENTINEL_PASS
  }
});
Defensive patterns

Strategy: validation

Validate before calling

function buildSentinelClientOptions(opts) {
  if (opts && opts.url !== undefined) {
    throw new Error('sentinelClientOptions must not contain a url; use socket + credentials');
  }
  return opts;
}
// before constructing the Sentinel client:
const sentinelClientOptions = buildSentinelClientOptions(rawOpts);

Type guard

function isValidSentinelClientOptions(o: unknown): o is Record<string, unknown> {
  return typeof o === 'object' && o !== null && !('url' in o && o.url !== undefined);
}

Try / catch

try {
  const client = factory.createClient({ sentinelClientOptions });
} catch (e) {
  if (e instanceof Error && /invalid sentinelClientOptions/.test(e.message)) {
    // strip url and retry, or surface a config error to the operator
  }
  throw e;
}

Prevention

When it happens

Trigger: Constructing RedisSentinelFactory / RedisSentinelClient with options.sentinelClientOptions = { url: 'redis://host:6379' }. Also triggered by passing a RedisClientOptions object built from a `redis://` URL string (e.g. via parseURL) as sentinelClientOptions.

Common situations: Copy-pasting a normal RedisClient options object (which often carries `url`) into the Sentinel `sentinelClientOptions` slot; reusing TLS/auth options derived from a URL for the sentinel monitor connections.

Related errors


AI-assisted analysis of redis/node-redis@bb5beb5657 (2026-08-03). Data as JSON: /data/errors/fa533cced956d87a.json. Report an issue: GitHub.