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?: falseView on GitHub (pinned to bb5beb5657)
Solutions
- Remove the `url` field from sentinelClientOptions — the Sentinel client supplies host/port per discovered node.
- Move connection details into sentinelClientOptions.socket and sentinelClientOptions.{username,password} instead of a URL.
- If you need URL-style config for the *data* nodes, put it on nodeClientOptions (also url-free) or use socket.host/port plus credentials.
- 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
- Construct sentinelClientOptions as an object literal; never spread a parseURL() result into it.
- Add a unit test asserting your config builder never emits a `url` key in the sentinel options.
- Share a single typed builder for sentinelClientOptions across environments.
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
- Reconnect strategy should return `false | Error | number`, g
- Client Side Caching is only supported with RESP3
- invalid nodeClientOptions for Sentinel
- no valid master node
- Master Node Not Enumerated
AI-assisted analysis of redis/node-redis@bb5beb5657 (2026-08-03).
Data as JSON: /data/errors/fa533cced956d87a.json.
Report an issue: GitHub.