redis/redis-py · critical · MasterNotFoundError
No master found for
Error message
No master found for {service_name!r}{error_info} What it means
Raised by Sentinel.discover_master() (redis/sentinel.py:384) after iterating every configured sentinel and finding none that reports a master in a healthy state for service_name. A sentinel 'passes' only if sentinel_masters() returns the service, state['is_master'] is True, the node is not in SDOWN/ODOWN, and num-other-sentinels >= self.min_other_sentinels (check_master_state, sentinel.py:343-349). error_info appends any per-sentinel ConnectionError/TimeoutError collected during the loop, so the message tells you which sentinels were unreachable.
Solutions
- Inspect error_info in the message — it lists each unreachable sentinel and the underlying error; fix reachability first.
- Verify service_name with `redis-cli -p <sentinel_port> SENTINEL masters` against each sentinel.
- If mid-failover, retry with backoff — discovery succeeds once a new master is elected and quorum agrees.
- Lower Sentinel(..., min_other_sentinels=N) if it exceeds your actual sentinel count minus one.
- Confirm network connectivity (telnet/ping) from the client to every sentinel host:port in the sentinels list.
Example fix
# before
s = redis.sentinel.Sentinel([('sent1', 26379)], min_other_sentinels=3)
s.master_for('mymaster') # MasterNotFoundError: No master found for 'mymaster' : ...
# after: retry with backoff and verify service_name/quorum
import time, redis
for attempt in range(10):
try:
s.discover_master('mymaster'); break
except redis.exceptions.MasterNotFoundError:
time.sleep(0.2 * (2 ** attempt))
else:
raise Defensive patterns
Strategy: retry
Validate before calling
import socket
def sentinels_reachable(sentinels, timeout=0.5) -> bool:
# call before relying on master discovery
for host, port in sentinels:
try:
with socket.create_connection((host, port), timeout=timeout):
pass
except OSError:
return False
return True Try / catch
import redis.exceptions, time
def discover_master_with_retry(sentinel, service_name, retries=10, base=0.2):
last = None
for attempt in range(retries):
try:
return sentinel.discover_master(service_name)
except redis.exceptions.MasterNotFoundError as e:
last = e
time.sleep(base * (2 ** attempt))
raise last Prevention
- Use a sentinel list with >= 3 nodes so quorum survives one being down.
- Set min_other_sentinels <= (sentinel_count - 1) to avoid over-strict quorum.
- Verify service_name against `SENTINEL masters` on every sentinel during deploy.
When it happens
Trigger: First connection (or re-discovery) calls discover_master(service_name); every sentinel either raises ConnectionError/TimeoutError (collected into error_info), or returns no state for service_name, or returns state failing check_master_state (not master, sdown, odown, or insufficient peer sentinels). The loop completes with no return and raises MasterNotFoundError at sentinel.py:384.
Common situations: All sentinels unreachable (network partition, wrong host/port); service_name typo so no sentinel knows it; quorum not yet reached mid-failover (old master down, new master not elected); min_other_sentinels configured higher than (sentinel_count - 1); client isolated from the sentinel quorum.
Related errors
- The previous master is now a slave
- No slave found for
- The previous master is now a slave
- Cannot set active database, database is unhealthy
- Cannot set active database, database is unhealthy
AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10).
Data as JSON: /api/errors/3d297feb3a284f64.
Report an issue: GitHub.
Appendix: source
Thrown at redis/sentinel.py:384
state = masters.get(service_name)
if state and self.check_master_state(state, service_name):
# Put this sentinel at the top of the list
self.sentinels[0], self.sentinels[sentinel_no] = (
sentinel,
self.sentinels[0],
)
ip = (
self._force_master_ip
if self._force_master_ip is not None
else state["ip"]
)
return ip, state["port"]
error_info = ""
if len(collected_errors) > 0:
error_info = f" : {', '.join(collected_errors)}"
raise MasterNotFoundError(f"No master found for {service_name!r}{error_info}")
def filter_slaves(self, slaves):
"Remove slaves that are in an ODOWN or SDOWN state"
slaves_alive = []
for slave in slaves:
if slave["is_odown"] or slave["is_sdown"]:
continue
slaves_alive.append((slave["ip"], slave["port"]))
return slaves_alive
def filter_replicas(self, replicas):
"""Remove replicas that are in an ODOWN or SDOWN state.
This is an alias for :py:meth:`filter_slaves`,
using the preferred Redis 5.0+ terminology.
"""
return self.filter_slaves(replicas)
View on GitHub (pinned to 6a6b581b48)