redis/node-redis · error · Error

invalid nodeClientOptions for Sentinel

Error message

invalid nodeClientOptions for Sentinel

What it means

RedisSentinelInternal rejects nodeClientOptions that contain a url field. Sentinel discovers master/replica host:port from Sentinel itself (and applies nodeAddressMap), so a static url on node clients would conflict with the discovered topology and is not allowed. Use socket.host/socket.port or nodeAddressMap for address remapping instead.

Source

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

    this.#name = options.name;
    this.#sentinelClientId = sentinelClientId;

    this.#RESP = options.RESP;
    this.#keyPrefix = options.keyPrefix;
    this.#sentinelSeedNodes = Array.from(options.sentinelRootNodes);
    // Initial root nodes start as a copy of the seed nodes; transform() later
    // merges discovered nodes on top while preserving these seeds.
    this.#sentinelRootNodes = Array.from(this.#sentinelSeedNodes);
    this.#maxCommandRediscovers = options.maxCommandRediscovers ?? 16;
    this.#masterPoolSize = options.masterPoolSize ?? 1;
    this.#replicaPoolSize = options.replicaPoolSize ?? 0;
    this.#nodeAddressMap = options.nodeAddressMap;
    this.#scanInterval = options.scanInterval ?? 0;
    this.#passthroughClientErrorEvents = options.passthroughClientErrorEvents ?? false;

    this.#nodeClientOptions = (options.nodeClientOptions ? {...options.nodeClientOptions} : {}) as RedisClientOptions<M, F, S, RESP, TYPE_MAPPING, RedisTcpSocketOptions>;
    if (this.#nodeClientOptions.url !== undefined) {
      throw new Error("invalid nodeClientOptions for Sentinel");
    }
    // One fieldset registry across master/replica node clients: fieldsets registered before
    // 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;

View on GitHub (pinned to bb5beb5657)

Solutions

  1. Remove the url field from nodeClientOptions — set socket.host/socket.port only if needed (usually not; Sentinel provides addresses).
  2. Use nodeAddressMap to remap discovered Sentinel addresses to reachable host:port pairs (e.g. for Docker/TLS front-ends).
  3. Put connection-level options like TLS in nodeClientOptions.socket without a url.
  4. Destructure out url when reusing an existing options object: const { url, ...rest } = opts.

Example fix

// before
createSentinel({ nodeClientOptions: { url: 'redis://10.0.0.1:6379', socket: { tls: true } }, ... });

// after
createSentinel({ nodeClientOptions: { socket: { tls: true } }, nodeAddressMap: { '10.0.0.1:6379': 'redis.internal:6379' }, ... });
Defensive patterns

Strategy: validation

Validate before calling

function validateNodeOpts(opts) { if (opts.nodeClientOptions?.url !== undefined) throw new Error('nodeClientOptions.url is forbidden for Sentinel'); }

Type guard

function sentinelNodeOptsValid(opts) { return opts.nodeClientOptions == null || opts.nodeClientOptions.url === undefined; }

Try / catch

// Construction-time error: strip url before constructing.

Prevention

When it happens

Trigger: Constructing createSentinel({ nodeClientOptions: { url: 'redis://...' } }). The constructor copies nodeClientOptions and explicitly checks for the presence of .url, throwing if set.

Common situations: Copying a RedisClientOptions object that was built with { url } from a standalone client into the sentinel config; attempting to pin a node address via url instead of nodeAddressMap; sharing a TLS/socket config object that happens to carry url.

Related errors


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