{"record":{"id":"5429aaee78688cae","repo":"pentaho/pentaho-kettle","slug":"error-closing","errorCode":null,"errorMessage":"Error closing ","messagePattern":"Error closing ","errorType":"exception","errorClass":"KettleDatabaseException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/pentaho/di/core/database/Database.java","lineNumber":1316,"sourceCode":"      closeable.close();\n    } catch ( Exception ex ) {\n      log.logError( \"Error closing \" + objDescription + \":\" + Const.CR + ex.getMessage() );\n      log.logError( Const.getStackTracker( ex ) );\n    }\n  }\n\n  /**\n   * Invokes the {@link AutoCloseable#close()} method on the given object, throwing a {@link KettleDatabaseException}\n   * encapsulating any exception that occurs.\n   *\n   * @param closeable      the object to close\n   * @param objDescription the description of the closeable object, used in exception message\n   */\n  protected void tryCloseAndThrow( AutoCloseable closeable, String objDescription ) throws KettleDatabaseException {\n    try {\n      closeable.close();\n    } catch ( Exception ex ) {\n      throw new KettleDatabaseException( \"Error closing \" + objDescription, ex );\n    }\n  }\n\n\n  public void closeInsert() throws KettleDatabaseException {\n    if ( prepStatementInsert != null ) {\n      tryCloseAndThrow( prepStatementInsert, \"insert prepared statement\" );\n      prepStatementInsert = null;\n    }\n  }\n\n  public void closeUpdate() throws KettleDatabaseException {\n    if ( prepStatementUpdate != null ) {\n      tryCloseAndThrow( prepStatementUpdate, \"update prepared statement\" );\n      prepStatementUpdate = null;\n    }\n  }\n","sourceCodeStart":1298,"sourceCodeEnd":1334,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/core/src/main/java/org/pentaho/di/core/database/Database.java#L1298-L1334","documentation":"Database.tryCloseAndThrow wraps any Exception thrown by AutoCloseable.close() (e.g. a JDBC PreparedStatement, Statement or ResultSet) into a KettleDatabaseException whose message is 'Error closing ' + the object description. It is thrown when releasing a JDBC resource fails, usually because the underlying connection is already broken or the statement is in an invalid state. The original exception is preserved as the cause.","triggerScenarios":"Calling closeInsert(), closeUpdate(), closeLookup() or any Database.close*() path that routes through tryCloseAndThrow when the underlying JDBC statement's close() throws SQLException — typically because the connection was already closed, dropped by the DB, or the statement was already closed in an invalid transaction state.","commonSituations":"Database/network connection dropped mid-step before cleanup; connection pool forcibly closed the physical connection; calling close twice on the same statement; DB server restart during a long-running transformation; driver-specific errors on close after a failed execute.","solutions":["Check the cause exception: if it says 'Connection is closed' or similar, the real problem is the lost connection — verify DB availability and network before blaming close()","Ensure the Database connection is still open and commit/rollback was done before closing statements","Avoid closing the same Database/statement resources twice in finally blocks","Check driver version compatibility; upgrade the JDBC driver if close() spuriously fails","Wrap close calls in a null-check/try-ignore so cleanup failures don't mask the original step error"],"exampleFix":"// before\ndatabase.closeInsert();\n// after\ntry {\n  database.closeInsert();\n} catch (KettleDatabaseException e) {\n  log.logError(\"Ignoring failure while closing insert statement\", e);\n}","handlingStrategy":"try-catch","validationCode":"if (database != null && !database.isAutoCommit()) { /* ensure commit/rollback done before close */ }","typeGuard":null,"tryCatchPattern":"try {\n  database.closeInsert();\n} catch (KettleDatabaseException e) {\n  log.logError(\"Failed closing insert statement: \" + e.getMessage(), e);\n  // inspect e.getCause() for the underlying SQLException\n}","preventionTips":["Commit or rollback before closing statements","Never close the same statement/Database twice","Monitor DB connection health during long runs","Keep JDBC drivers up to date"],"tags":["jdbc","resource-cleanup","database"],"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"}