redis/node-redis · error · Error
no valid master node
Error message
no valid master node
What it means
Thrown by analyze() when parseNode(observed.masterData) returns undefined (sentinel/index.ts:1369). parseNode extracts host/port from the SENTINEL MASTER reply and rejects entries whose flags indicate the node is not a usable master; the trace logs `because ${observed.masterData.flags}`. So a sentinel was reached and replied, but the master it reported could not be parsed into a valid master node.
Source
Thrown at packages/client/lib/sentinel/index.ts:1371
this.#trace(`observe: error ${err}`);
this.emit('error', err);
} finally {
if (client !== undefined && client.isOpen) {
this.#trace(`observe: destroying sentinel client`);
client.destroy();
}
}
}
this.#trace(`observe: none of the sentinels are available`);
throw new Error('None of the sentinels are available');
}
analyze(observed: Awaited<ReturnType<RedisSentinelInternal<M, F, S, RESP, TYPE_MAPPING>["observe"]>>) {
let master = parseNode(observed.masterData);
if (master === undefined) {
this.#trace(`analyze: no valid master node because ${observed.masterData.flags}`);
throw new Error("no valid master node");
}
if (master.host === observed.currentMaster?.host && master.port === observed.currentMaster?.port) {
this.#trace(`analyze: master node hasn't changed from ${observed.currentMaster?.host}:${observed.currentMaster?.port}`);
master = undefined;
} else {
this.#trace(`analyze: master node has changed to ${master.host}:${master.port} from ${observed.currentMaster?.host}:${observed.currentMaster?.port}`);
}
let sentinel: RedisNode | undefined = observed.sentinelConnected;
if (sentinel.host === observed.currentSentinel?.host && sentinel.port === observed.currentSentinel.port) {
this.#trace(`analyze: sentinel node hasn't changed`);
sentinel = undefined;
} else {
this.#trace(`analyze: sentinel node has changed to ${sentinel.host}:${sentinel.port}`);
}
const replicasToClose: Array<RedisNode> = [];View on GitHub (pinned to bb5beb5657)
Solutions
- Confirm options.name exactly matches the master name in `sentinel masters` output on your sentinel.
- Run `redis-cli -h <sentinel> -p 26379 sentinel master <name>` and inspect the flags/host/port fields.
- If the master is flagged down, wait for failover to elect a new master and let the retry loop (maxCommandRediscovers) recover.
- Point sentinelRootNodes at sentinels that actually monitor the named master.
Defensive patterns
Strategy: validation
Validate before calling
// Validate the master name against a reachable sentinel before connecting.
import { createClient } from '@redis/client';
async function assertMasterMonitored(sentinelNode, name) {
const c = createClient({ socket: sentinelNode, modules: undefined });
c.on('error', () => {});
await c.connect();
try {
const masters = await c.sentinel.sentinelMasters();
if (!masters.some(m => m.name === name)) {
throw new Error(`sentinel does not monitor master '${name}'`);
}
} finally {
await c.destroy();
}
} Try / catch
try {
await sentinel.connect();
} catch (e) {
if (e instanceof Error && /no valid master node/.test(e.message)) {
// options.name is wrong or master is failing over; surface to operator
}
throw e;
} Prevention
- Treat options.name as a checked constant derived from sentinel.conf, not free text.
- Log/inspect observed.masterData.flags in an 'error' handler to diagnose.
- Allow the bounded retry loop (maxCommandRediscovers) to ride out failovers before surfacing.
When it happens
Trigger: The monitored name (options.name) does not match any master the sentinel monitors (SENTINEL MASTER returns an error/empty shape); the master is flagged down/disconnected in a way parseNode rejects; a sentinel version returning a malformed master record.
Common situations: Typo in options.name vs the actual master name configured in sentinel.conf; pointing at a sentinel that monitors a different deployment; sentinel mid-failover where the master record is transitional.
Related errors
- Master Node Not Enumerated
- One (or more) of the watched keys has been changed
- Scan iteration was interrupted by a Sentinel master change
- Client Side Caching is only supported with RESP3
- invalid nodeClientOptions for Sentinel
AI-assisted analysis of redis/node-redis@bb5beb5657 (2026-08-03).
Data as JSON: /data/errors/1aadfdc2a6edf07d.json.
Report an issue: GitHub.