redis/jedis · error · JedisException

is not connected to a Connection.

Error message

<class> is not connected to a Connection.

What it means

JedisSafeAuthenticator.sendAndFlushCommand() needs an underlying Connection to send the AUTH/token-refresh command. If the internal client reference is null, no connection is attached, so it throws JedisException(getClass() + " is not connected to a Connection."). This happens inside safeReAuthenticate, i.e. while trying to transparently re-authenticate the connection.

Solutions

  1. Ensure the connection stays open for the lifetime of the authenticator; check for premature close()/disconnect calls.
  2. Verify token-refresh lifecycle: don't close connections while safeReAuthenticate may be in flight.
  3. Upgrade Jedis — newer versions harden the re-auth path against this race.
  4. Recreate the client/connection after this error; the authenticator state is unusable.

Example fix

// before
connection.close(); // then token expires
// safeReAuthenticate -> JedisException: not connected
// after
try {
  // keep connection open until re-auth completes
  connection.ping();
} catch (JedisConnectionException e) {
  client.renewConnection(); // rebuild before token refresh is needed
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (connection == null || !connection.isConnected()) { /* rebuild connection before token ops */ }

Type guard

boolean authenticatorReady(JedisSafeAuthenticator a) { return a != null && a.isConnected(); }

Try / catch

try {
  client.safeAuth();
} catch (JedisException e) {
  if (e.getMessage().contains("is not connected to a Connection")) {
    client.rebuildConnection(); // recreate and re-authenticate
  } else throw e;
}

Prevention

When it happens

Trigger: safeReAuthenticate() triggering sendAndFlushCommand() when the authenticator's client field is null — the authenticator was created but never wired to a live Connection, or the connection was closed/nulled before token refresh ran.

Common situations: Using token-based authentication (IAM/SToken) with a connection that was closed concurrently; a race where re-auth fires after connection teardown; misconfigured client construction where the authenticator is instantiated without a connection.

Related errors


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

Appendix: source

Thrown at src/main/java/redis/clients/jedis/JedisSafeAuthenticator.java:35

import redis.clients.jedis.exceptions.JedisException;
import redis.clients.jedis.util.SafeEncoder;

class JedisSafeAuthenticator {

  private static final Token PLACEHOLDER_TOKEN = new SimpleToken(null, null, 0, 0, null);
  private static final Logger logger = LoggerFactory.getLogger(JedisSafeAuthenticator.class);

  protected volatile Connection client;
  protected final Consumer<Object> authResultHandler = this::processAuthReply;
  protected final Consumer<Token> authenticationHandler = this::safeReAuthenticate;

  protected final AtomicReference<Token> pendingTokenRef = new AtomicReference<Token>(null);
  protected final ReentrantLock commandSync = new ReentrantLock();
  protected final Queue<Consumer<Object>> resultHandler = new ConcurrentLinkedQueue<Consumer<Object>>();

  protected void sendAndFlushCommand(Command command, Object... args) {
    if (client == null) {
      throw new JedisException(getClass() + " is not connected to a Connection.");
    }
    CommandArguments cargs = new CommandArguments(command).addObjects(args);

    Token newToken = pendingTokenRef.getAndSet(PLACEHOLDER_TOKEN);

    // lets send the command without locking !!IF!! we know that pendingTokenRef is null replaced with PLACEHOLDER_TOKEN and no re-auth will go into action
    // !!ELSE!! we are locking since we already know a re-auth is still in progress in another thread and we need to wait for it to complete, we do nothing but wait on it!
    if (newToken != null) {
      commandSync.lock();
    }
    try {
      client.sendCommand(cargs);
      client.flush();
    } finally {
      Token newerToken = pendingTokenRef.getAndSet(null);
      // lets check if a newer token received since the beginning of this sendAndFlushCommand call
      if (newerToken != null && newerToken != PLACEHOLDER_TOKEN) {
        safeReAuthenticate(newerToken);

View on GitHub (pinned to 6dac31d4c2)