{"record":{"id":"2087fbeee1505d13","repo":"redis/jedis","slug":"failed-to-set-so-timeout","errorCode":null,"errorMessage":"Failed to set SO_TIMEOUT","messagePattern":"Failed to set SO_TIMEOUT","errorType":"exception","errorClass":"JedisConnectionException","httpStatus":null,"severity":"error","filePath":"src/main/java/redis/clients/jedis/Connection.java","lineNumber":415,"sourceCode":"   */\n  public void setSoTimeout(int millis) {\n    defaultTimeoutSource.setDefaults(millis, defaultTimeoutSource.getDefaults().blockingTimeout);\n    applyCurrentTimeout();\n  }\n\n  private int currentTimeout() {\n    return isBlocking ? defaultTimeoutSource.get().blockingTimeout : defaultTimeoutSource.get().timeout;\n  }\n\n  void applyCurrentTimeout() {\n    int timeout = currentTimeout();\n     if (timeout == appliedSoTimeout || socket == null) {\n      return;\n    }\n    try {\n      socket.setSoTimeout(timeout);\n    } catch (SocketException e) {\n      throw markBroken(new JedisConnectionException(\"Failed to set SO_TIMEOUT\", e));\n    }\n    appliedSoTimeout = timeout;\n    if (logger.isTraceEnabled()) {\n      logger.trace(\"Timeout applied millis={} blocking={} conn={}\", timeout, isBlocking,\n        toIdentityString());\n    }\n  }\n\n  /**\n   * Sets the socket read timeout (SO_TIMEOUT) to infinite for blocking commands.\n   *\n   * <p>The effective timeout applied depends on the current connection state:</p>\n   * <ul>\n   *   <li>If relaxed timeout mode is active, the looser of the configured blocking timeout and\n   *   the relaxed blocking timeout is used, {@code 0} (infinite) being the loosest.</li>\n   *   <li>Otherwise, the configured blocking timeout is applied.</li>\n   * </ul>\n   *","sourceCodeStart":397,"sourceCodeEnd":433,"githubUrl":"https://github.com/redis/jedis/blob/6dac31d4c224fb3257c216f3985340c6f500cdcb/src/main/java/redis/clients/jedis/Connection.java#L397-L433","documentation":"Connection.applyCurrentTimeout sets the socket's SO_TIMEOUT to match the connection's current timeout. If the underlying socket refuses (SocketException), the connection is marked broken and a JedisConnectionException is thrown. This typically means the socket has been closed or is otherwise unusable at the OS level.","triggerScenarios":"Calling setTimeoutInfinite/rollbackTimeout/setSoTimeout, or any command path that re-applies the timeout (connect, readProtocolWithCheckingBroken, readPushesWithCheckingBroken) when the socket is already closed, reset by a peer, or set after socket close on a broken connection.","commonSituations":"A server or middlebox closed the TCP connection and the client later tries to change the timeout; sharing a Connection across threads where one closed it; socket closed during failover; calling timeout APIs after explicitly closing the connection.","solutions":["Discard the connection object — it is marked broken and returned to the pool as unusable; obtain a fresh connection from the pool.","Audit for concurrent use or manual close() of Connection objects from multiple threads.","Check for aggressive firewalls/LB idle timeouts killing the socket between commands.","If using timeouts around blocking commands, wrap in retry logic that reconnects on JedisConnectionException."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// guard timeout changes to live, thread-owned connections only\nif (connection != null && !isClosed(connection)) {\n  connection.setSoTimeout(ms);\n}","typeGuard":null,"tryCatchPattern":"try {\n  connection.setTimeoutInfinite();\n  // blocking command\n} catch (JedisConnectionException e) {\n  connection = pool.getResource(); // socket was dead; take a fresh one\n}","preventionTips":["Never share a Connection across threads","Don't mutate timeouts on connections you didn't open","Tune pool eviction so dead sockets are replaced early","Investigate idle-kill behavior of firewalls/LBs between client and Redis"],"tags":["redis","socket","timeout","broken-connection"],"backgroundTag":"request-timeout","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"}