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

  1. Inspect error_info in the message — it lists each unreachable sentinel and the underlying error; fix reachability first.
  2. Verify service_name with `redis-cli -p <sentinel_port> SENTINEL masters` against each sentinel.
  3. If mid-failover, retry with backoff — discovery succeeds once a new master is elected and quorum agrees.
  4. Lower Sentinel(..., min_other_sentinels=N) if it exceeds your actual sentinel count minus one.
  5. 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

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


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)