{"record":{"id":"18054b753ea948c6","repo":"redis/jedis","slug":"could-not-return-the-broken-resource-to-the-pool","errorCode":null,"errorMessage":"Could not return the broken resource to the pool","messagePattern":"Could not return the broken resource to the pool","errorType":"exception","errorClass":"JedisException","httpStatus":null,"severity":"error","filePath":"src/main/java/redis/clients/jedis/util/Pool.java","lineNumber":64,"sourceCode":"  public void returnResource(final T resource) {\n    if (resource == null) {\n      return;\n    }\n    try {\n      super.returnObject(resource);\n    } catch (RuntimeException e) {\n      throw new JedisException(\"Could not return the resource to the pool\", e);\n    }\n  }\n\n  public void returnBrokenResource(final T resource) {\n    if (resource == null) {\n      return;\n    }\n    try {\n      super.invalidateObject(resource);\n    } catch (Exception e) {\n      throw new JedisException(\"Could not return the broken resource to the pool\", e);\n    }\n  }\n\n  @Override\n  public void addObjects(int count) {\n    try {\n      for (int i = 0; i < count; i++) {\n        addObject();\n      }\n    } catch (Exception e) {\n      throw new JedisException(\"Error trying to add idle objects\", e);\n    }\n  }\n}\n","sourceCodeStart":46,"sourceCodeEnd":79,"githubUrl":"https://github.com/redis/jedis/blob/6dac31d4c224fb3257c216f3985340c6f500cdcb/src/main/java/redis/clients/jedis/util/Pool.java#L46-L79","documentation":"Pool.returnBrokenResource(resource) invalidates a defective connection via commons-pool2 invalidateObject. If invalidation throws, it is wrapped in JedisException(\"Could not return the broken resource to the pool\"). The broken connection could not be discarded cleanly.","triggerScenarios":"Calling returnBrokenResource with an object already invalidated, not borrowed from this pool, or borrowed after destroy(); underlying factory destroyObject throwing (e.g. socket close error on a dead connection).","commonSituations":"Error-handling paths that call returnBrokenResource after the pool was already shut down; marking the same broken connection broken twice (e.g. in both a catch block and finally).","solutions":["Ensure returnBrokenResource is called at most once per resource — use a flag or structure so catch and finally don't both run it.","Check pool lifecycle: don't return/invalidate resources after destroy().","Inspect getCause() for the underlying factory/socket failure.","Prefer try-with-resources on Jedis, which routes broken resources correctly."],"exampleFix":"// before\n} catch (JedisException e) {\n  pool.returnBrokenResource(jedis);\n} finally {\n  pool.returnBrokenResource(jedis); // second invalidate -> throws\n}\n// after\n} catch (JedisException e) {\n  pool.returnBrokenResource(jedis);\n} finally {\n  pool.returnResource(jedis); // invalidateObject is idempotent-safe in pool2; or guard with boolean flag\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  pool.returnBrokenResource(resource);\n} catch (JedisException e) {\n  log.warn(\"Failed to invalidate broken resource\", e.getCause());\n}","preventionTips":["Call returnBrokenResource at most once per resource.","Prefer try-with-resources on Jedis for correct broken-resource routing.","Don't invalidate resources after pool.destroy()."],"tags":["pool","broken-resource","resource-cleanup"],"backgroundTag":"invalid-state-transition","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"}