redis/redis-py · error · NoValidDatabaseException
Cannot set active database, database is unhealthy
Error message
Cannot set active database, database is unhealthy
What it means
Raised by `MultiDBClient.set_active_database()` (redis/asyncio/multidb/client.py:175) when the target database is a registered member but its circuit breaker is not in the CLOSED state after a fresh `_check_db_health()` call. Promoting an OPEN/HALF_OPEN database as active would route commands to a known-unhealthy endpoint, so the client refuses with NoValidDatabaseException.
Source
Thrown at redis/asyncio/multidb/client.py:175
for existing_db, _ in self._databases:
if existing_db == database:
exists = True
break
if not exists:
raise ValueError("Given database is not a member of database list")
await self._check_db_health(database)
if database.circuit.state == CBState.CLOSED:
highest_weighted_db, _ = self._databases.get_top_n(1)[0]
await self.command_executor.set_active_database(
database, GeoFailoverReason.MANUAL
)
return
raise NoValidDatabaseException(
"Cannot set active database, database is unhealthy"
)
async def add_database(
self, config: DatabaseConfig, skip_initial_health_check: bool = True
):
"""
Adds a new database to the database list.
Args:
config: DatabaseConfig object that contains the database configuration.
skip_initial_health_check: If True, adds the database even if it is unhealthy.
"""
# The retry object is not used in the lower level clients, so we can safely remove it.
# We rely on command_retry in terms of global retries.
config.client_kwargs.update({"retry": Retry(retries=0, backoff=NoBackoff())})
if config.from_url:View on GitHub (pinned to da03cdc7e8)
Solutions
- Wait for the target database's circuit to recover to CLOSED (monitor via health checks) and retry `set_active_database`.
- Pick a different database from `get_databases()` whose circuit is CLOSED.
- Tune the circuit breaker (`grace_period`) and health-check probes so transient slowness does not trip the circuit.
- Verify the underlying Redis endpoint is actually reachable and responsive before attempting the switch.
Example fix
# before
await client.set_active_database(target_db) # NoValidDatabaseException
# after
from redis.multidb.circuit import State as CBState
healthy = [db for db, _ in client.get_databases() if db.circuit.state == CBState.CLOSED]
if healthy:
await client.set_active_database(healthy[0])
else:
# wait for recovery or alert
raise RuntimeError('no healthy database to promote') Defensive patterns
Strategy: validation
Validate before calling
from redis.multidb.circuit import State as CBState
async def can_promote(client, database) -> bool:
await client._check_db_health(database) # refresh circuit state
return database.circuit.state == CBState.CLOSED
# gate set_active_database on this returning True Type guard
from redis.multidb.circuit import State as CBState
def circuit_is_closed(database) -> bool:
return database.circuit.state == CBState.CLOSED Try / catch
from redis.multidb.exception import NoValidDatabaseException
try:
await client.set_active_database(db)
except NoValidDatabaseException as e:
if 'unhealthy' in str(e):
# wait for recovery, or pick another CLOSED db
...
raise Prevention
- Check `database.circuit.state == CBState.CLOSED` right before promotion.
- Drive manual failover only after confirming the target passes a fresh health check.
- Tune circuit-breaker `grace_period` and health-check probes to avoid stuck OPEN states.
When it happens
Trigger: Calling `await client.set_active_database(db)` for a database whose latest health check failed (circuit OPEN), or which is in HALF_OPEN awaiting probe recovery. The health check at client.py:166 runs immediately before the circuit-state check at client.py:168.
Common situations: Manually failing over to a database that is still down; race where the DB goes unhealthy between the membership check and the health check; aggressive circuit-breaker thresholds marking a slow DB as OPEN.
Related errors
- Initial connection failed - no active database found
- No valid database available for communication
- No database connections currently available. This is a tempo
- Unhealthy database
- Initial health check failed. Initial health check policy: {s
AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04).
Data as JSON: /data/errors/73bebfdeefeaf707.json.
Report an issue: GitHub.