redis/jedis · error · JedisConnectionException

No healthy database available after initialization policy…

Error message

No healthy database available after initialization policy succeeded.

What it means

selectBestAvailableDatabase is only called after the InitializationPolicy reported SUCCESS, yet when it scans databases in weight order it expects to find at least one healthy database. If every status check comes back unhealthy anyway (statuses changed between the policy evaluation and the selection, or no health check is configured and status is still unhealthy), this defensive JedisConnectionException is thrown. Per the source comment, it 'should not happen if policy succeeded', indicating a race or inconsistent health state.

Solutions

  1. Retry client construction; if transient, a healthy state at build time avoids the race.
  2. If using a custom InitializationPolicy, ensure its SUCCESS decision actually requires at least one healthy database.
  3. Investigate why all endpoints turned unhealthy in that instant (check health-check logs and Redis server availability).
  4. Tune health check thresholds so borderline/flapping endpoints are not toggling status during startup.

Example fix

// before — custom policy can report SUCCESS with zero healthy dbs
public Decision evaluate(ctx) {
  return ctx.getTotalCount() > 0 ? Decision.SUCCESS : Decision.FAIL;
}
// after — require at least one healthy database
public Decision evaluate(ctx) {
  return ctx.getHealthyCount() > 0 ? Decision.SUCCESS : Decision.FAIL;
}
Defensive patterns

Strategy: retry

Try / catch

try {
  client = MultiDbClient.builder().multiDbConfig(cfg).build();
} catch (JedisConnectionException e) {
  if (e.getMessage().contains("No healthy database available after initialization")) {
    // transient race — rebuild after a short delay
    Thread.sleep(1000);
    client = MultiDbClient.builder().multiDbConfig(cfg).build();
  }
}

Prevention

When it happens

Trigger: waitForInitializationPolicy gets Decision.SUCCESS from the policy, then selectBestAvailableDatabase iterates sortedDatabases and healthStatusManager.getHealthStatus(endpoint) returns unhealthy for every endpoint — a race where health statuses flip to unhealthy between policy evaluation and database selection, or a policy that succeeds despite no healthy status (e.g. a custom policy).

Common situations: All databases become unhealthy in the window between policy evaluation and selection (mass outage starting exactly at startup); a custom InitializationPolicy whose SUCCESS logic does not require any healthy database; flapping health checks that pass at evaluation time and fail moments later.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of redis/jedis@6dac31d4c2 (2026-09-08). Data as JSON: /api/errors/3ffeef734db208d1. Report an issue: GitHub.

Appendix: source

Thrown at src/main/java/redis/clients/jedis/mcf/MultiDbConnectionProvider.java:502

      // Check if health checks are enabled for this endpoint
      if (healthStatusManager.hasHealthCheck(endpoint)) {
        status = healthStatusManager.getHealthStatus(endpoint);
      } else {
        // No health check configured - assume healthy
        log.info("No health check configured for database {}, defaulting to HEALTHY", endpoint);
        status = HealthStatus.HEALTHY;
      }

      if (status.isHealthy()) {
        log.info("Found healthy database: {} (weight: {})", endpoint, database.getWeight());
        return database;
      } else {
        log.info("Database {} is unhealthy, trying next database", endpoint);
      }
    }

    // No healthy database found (should not happen if policy succeeded)
    throw new JedisConnectionException(
        "No healthy database available after initialization policy succeeded.");
  }

  /**
   * Periodic failback checker - runs at configured intervals to check for failback opportunities
   */
  @VisibleForTesting
  void periodicFailbackCheck() {
    try {
      // Find the best candidate database for failback
      Map.Entry<Endpoint, Database> bestCandidate = null;
      float bestWeight = activeDatabase.getWeight();

      for (Map.Entry<Endpoint, Database> entry : databaseMap.entrySet()) {
        Database database = entry.getValue();

        // Skip if this is already the active database
        if (database == activeDatabase) {

View on GitHub (pinned to 6dac31d4c2)