{"record":{"id":"1c72a2d8d683f67c","repo":"tursodatabase/turso","slug":"statement-is-closed","errorCode":null,"errorMessage":"statement is closed","messagePattern":"statement is closed","errorType":"exception","errorClass":"SQLException","httpStatus":null,"severity":"error","filePath":"bindings/java/src/main/java/tech/turso/jdbc4/JDBC4Statement.java","lineNumber":432,"sourceCode":"  public boolean isClosed() throws SQLException {\n    return this.closed;\n  }\n\n  @Override\n  public void setPoolable(boolean poolable) throws SQLException {\n    // TODO\n  }\n\n  @Override\n  public boolean isPoolable() throws SQLException {\n    // TODO\n    return false;\n  }\n\n  @Override\n  public void closeOnCompletion() throws SQLException {\n    if (closed) {\n      throw new SQLException(\"statement is closed\");\n    }\n    closeOnCompletion = true;\n  }\n\n  /**\n   * Indicates whether the statement should be closed automatically when all its dependent result\n   * sets are closed.\n   */\n  @Override\n  public boolean isCloseOnCompletion() throws SQLException {\n    if (closed) {\n      throw new SQLException(\"statement is closed\");\n    }\n    return closeOnCompletion;\n  }\n\n  @Override\n  @SkipNullableCheck","sourceCodeStart":414,"sourceCodeEnd":450,"githubUrl":"https://github.com/tursodatabase/turso/blob/244cde92a7df7f9b8b8b7a4075c35a12977e303e/bindings/java/src/main/java/tech/turso/jdbc4/JDBC4Statement.java#L414-L450","documentation":"closeOnCompletion() flags a statement to be closed automatically once its result sets are closed. JDBC4Statement refuses to set the flag on a closed statement: `if (closed) throw new SQLException(\"statement is closed\")`. Statements also become closed when their connection is closed.","triggerScenarios":"Calling stmt.closeOnCompletion() after stmt.close(); after the owning connection was closed (connection close cascades to statements); on a statement reclaimed or evicted by a pool; configuring a statement pulled from an app-level cache that was already shut down.","commonSituations":"Setup logic split across methods so close() (or try-with-resources) runs before the configuration call; web handlers reusing statements cached beyond the request; pool eviction (idle timeout, invalidation on error) closing statements underneath the application.","solutions":["Call closeOnCompletion() immediately after creating the statement, before any execution or close path","Guard the call with `if (!stmt.isClosed())`","Do not cache statements across request lifecycles; let the pool manage connections only","Check connection.isValid()/isClosed() first when a pool may have intervened"],"exampleFix":"// before\ntry (Statement stmt = conn.createStatement()) {\n  ...\n} // stmt closed here\nstmt.closeOnCompletion(); // too late -> SQLException\n\n// after\nStatement stmt = conn.createStatement();\nstmt.closeOnCompletion(); // configure right after creation\ntry (stmt) {\n  ...\n}","handlingStrategy":"validation","validationCode":"if (!stmt.isClosed()) {\n  stmt.closeOnCompletion();\n}","typeGuard":null,"tryCatchPattern":"try {\n  stmt.closeOnCompletion();\n} catch (SQLException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"statement is closed\")) {\n    // already closed: nothing to configure\n  } else {\n    throw e;\n  }\n}","preventionTips":["Configure closeOnCompletion immediately after createStatement, before any execution","Check isClosed() before lifecycle configuration calls","Closing the connection closes its statements — verify connection state when pools are involved"],"tags":["java","jdbc","turso","statement","lifecycle","closed-resource"],"backgroundTag":"resource-closed","analyzedSha":"244cde92a7df7f9b8b8b7a4075c35a12977e303e","analyzedAt":"2026-08-20T07:02:18.389Z","contentChangedAt":"2026-08-20T07:02:18.389Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}