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
- Remove `url` from `sentinelClientOptions`; supply sentinel endpoints via `rootNodes`.
- Keep only auth/socket fields (e.g. `password`, TLS) in `sentinelClientOptions`.
- 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
- Keep sentinel endpoint addresses only in rootNodes.
- Store auth/TLS settings separately from URL-bearing option templates.
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
- invalid nodeClientOptions for Sentinel
- Client Side Caching is only supported with RESP3
- Master Node Not Enumerated
- no replicas available for read
- already attempting to open
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?: falseView on GitHub (pinned to 90fd0652bc)