{"record":{"id":"d36355958efc473b","repo":"pentaho/pentaho-kettle","slug":"error-closing-prepared-statement","errorCode":null,"errorMessage":"Error closing prepared statement","messagePattern":"Error closing prepared statement","errorType":"exception","errorClass":"KettleDatabaseException","httpStatus":null,"severity":"warning","filePath":"core/src/main/java/org/pentaho/di/core/database/Database.java","lineNumber":1285,"sourceCode":"      }\n    } catch ( SQLException ex ) {\n      throw new KettleDatabaseException( \"Couldn't prepare statement:\" + Const.CR + sql, ex );\n    }\n  }\n\n  public void closeLookup() throws KettleDatabaseException {\n    if ( pstmt != null ) {\n      closePreparedStatement( pstmt );\n      pstmt = null;\n    }\n  }\n\n  public void closePreparedStatement( PreparedStatement ps ) throws KettleDatabaseException {\n    if ( ps != null ) {\n      try {\n        ps.close();\n      } catch ( SQLException e ) {\n        throw new KettleDatabaseException( \"Error closing prepared statement\", e );\n      }\n    }\n  }\n\n  /**\n   * Invokes the {@link AutoCloseable#close()} method on the given object, logging any exceptions that occur.\n   *\n   * @param closeable      the object to close\n   * @param objDescription the description of the closeable object, used in logging\n   */\n  protected void tryCloseAndLog( AutoCloseable closeable, String objDescription ) {\n    try {\n      closeable.close();\n    } catch ( Exception ex ) {\n      log.logError( \"Error closing \" + objDescription + \":\" + Const.CR + ex.getMessage() );\n      log.logError( Const.getStackTracker( ex ) );\n    }\n  }","sourceCodeStart":1267,"sourceCodeEnd":1303,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/core/src/main/java/org/pentaho/di/core/database/Database.java#L1267-L1303","documentation":"KettleDatabaseException thrown by Database.closePreparedStatement(PreparedStatement) when ps.close() throws a SQLException. Purely a resource-release failure; the statement is being discarded anyway, so this usually signals a broken connection or driver quirk rather than lost data. Also reached via closeLookup()/closeInsert().","triggerScenarios":"Calling closePreparedStatement(ps) (or closeLookup/closeInsert) where ps.close() throws SQLException — connection already dead, driver-specific close failure, or double-close issues in some drivers.","commonSituations":"Cleanup in error paths after the DB connection dropped, drivers that throw on closing statements of a terminated session.","solutions":["Treat as non-fatal in cleanup paths: log and continue, since the statement is being released regardless","Check connection health; if the connection is dead, close/reconnect the whole Database object","Upgrade the driver if it throws spuriously on close","Ensure statements are closed before the connection so close order is correct"],"exampleFix":"// before\ntry { database.closeInsert(); } finally { database.disconnect(); }\n// after\ntry {\n  database.closeInsert();\n} catch ( KettleDatabaseException e ) {\n  log.warn(\"Failed to close prepared statement: \" + e.getMessage());\n} finally {\n  database.disconnect();\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  database.closePreparedStatement( ps );\n} catch ( KettleDatabaseException e ) {\n  log.warn( \"Statement close failed (non-fatal): \" + e.getMessage() );\n}","preventionTips":["Close statements before disconnecting the connection","Treat close failures in finally blocks as log-and-continue","Use consistent open/close pairing (openLookup/closeLookup) per connection lifecycle"],"tags":["jdbc","database","statement","cleanup"],"backgroundTag":"database-query-failed","analyzedSha":"f3058517a153da500bf4551f46d79b91bf8ec552","analyzedAt":"2026-09-13T14:04:16.340Z","contentChangedAt":"2026-09-13T14:04:16.340Z","schemaVersion":2},"datasetVersion":"2026-09-20T23:17:15.980Z"}