{"record":{"id":"5947c84144aa0ca4","repo":"redis/jedis","slug":"class-is-not-connected-to-a-connection","errorCode":null,"errorMessage":"<class> is not connected to a Connection.","messagePattern":"<class> is not connected to a Connection\\.","errorType":"exception","errorClass":"JedisException","httpStatus":null,"severity":"error","filePath":"src/main/java/redis/clients/jedis/JedisSafeAuthenticator.java","lineNumber":35,"sourceCode":"import redis.clients.jedis.exceptions.JedisException;\nimport redis.clients.jedis.util.SafeEncoder;\n\nclass JedisSafeAuthenticator {\n\n  private static final Token PLACEHOLDER_TOKEN = new SimpleToken(null, null, 0, 0, null);\n  private static final Logger logger = LoggerFactory.getLogger(JedisSafeAuthenticator.class);\n\n  protected volatile Connection client;\n  protected final Consumer<Object> authResultHandler = this::processAuthReply;\n  protected final Consumer<Token> authenticationHandler = this::safeReAuthenticate;\n\n  protected final AtomicReference<Token> pendingTokenRef = new AtomicReference<Token>(null);\n  protected final ReentrantLock commandSync = new ReentrantLock();\n  protected final Queue<Consumer<Object>> resultHandler = new ConcurrentLinkedQueue<Consumer<Object>>();\n\n  protected void sendAndFlushCommand(Command command, Object... args) {\n    if (client == null) {\n      throw new JedisException(getClass() + \" is not connected to a Connection.\");\n    }\n    CommandArguments cargs = new CommandArguments(command).addObjects(args);\n\n    Token newToken = pendingTokenRef.getAndSet(PLACEHOLDER_TOKEN);\n\n    // 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\n    // !!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!\n    if (newToken != null) {\n      commandSync.lock();\n    }\n    try {\n      client.sendCommand(cargs);\n      client.flush();\n    } finally {\n      Token newerToken = pendingTokenRef.getAndSet(null);\n      // lets check if a newer token received since the beginning of this sendAndFlushCommand call\n      if (newerToken != null && newerToken != PLACEHOLDER_TOKEN) {\n        safeReAuthenticate(newerToken);","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/redis/jedis/blob/6dac31d4c224fb3257c216f3985340c6f500cdcb/src/main/java/redis/clients/jedis/JedisSafeAuthenticator.java#L17-L53","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure the connection stays open for the lifetime of the authenticator; check for premature close()/disconnect calls.","Verify token-refresh lifecycle: don't close connections while safeReAuthenticate may be in flight.","Upgrade Jedis — newer versions harden the re-auth path against this race.","Recreate the client/connection after this error; the authenticator state is unusable."],"exampleFix":"// before\nconnection.close(); // then token expires\n// safeReAuthenticate -> JedisException: not connected\n// after\ntry {\n  // keep connection open until re-auth completes\n  connection.ping();\n} catch (JedisConnectionException e) {\n  client.renewConnection(); // rebuild before token refresh is needed\n}","handlingStrategy":"try-catch","validationCode":"if (connection == null || !connection.isConnected()) { /* rebuild connection before token ops */ }","typeGuard":"boolean authenticatorReady(JedisSafeAuthenticator a) { return a != null && a.isConnected(); }","tryCatchPattern":"try {\n  client.safeAuth();\n} catch (JedisException e) {\n  if (e.getMessage().contains(\"is not connected to a Connection\")) {\n    client.rebuildConnection(); // recreate and re-authenticate\n  } else throw e;\n}","preventionTips":["Don't close connections while token-based re-authentication may be pending.","Check connection liveness (ping) before long-lived background token operations.","Upgrade to a Jedis version with hardened re-auth lifecycle handling.","Avoid sharing the authenticated client across threads that may close it independently."],"tags":["auth","token-based-authentication","lifecycle"],"backgroundTag":"authentication-required","analyzedSha":"6dac31d4c224fb3257c216f3985340c6f500cdcb","analyzedAt":"2026-09-08T04:55:01.204Z","contentChangedAt":"2026-09-08T04:55:01.204Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}