{"record":{"id":"e37f27b44fc0476c","repo":"alibaba/druid","slug":"statement-is-closed","errorCode":null,"errorMessage":"statement is closed","messagePattern":"statement is closed","errorType":"exception","errorClass":"SQLException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/com/alibaba/druid/pool/DruidPooledStatement.java","lineNumber":183,"sourceCode":"    }\n\n    public DruidPooledConnection getPoolableConnection() {\n        return conn;\n    }\n\n    public Statement getStatement() {\n        return stmt;\n    }\n\n    protected void checkOpen() throws SQLException {\n        if (closed) {\n            Throwable disableError = null;\n            if (this.conn != null) {\n                disableError = this.conn.getDisableError();\n            }\n\n            if (disableError != null) {\n                throw new SQLException(\"statement is closed\", disableError);\n            } else {\n                throw new SQLException(\"statement is closed\");\n            }\n        }\n    }\n\n    protected void clearResultSet() {\n        if (resultSetTrace == null) {\n            return;\n        }\n\n        for (ResultSet rs : resultSetTrace) {\n            try {\n                if (!rs.isClosed()) {\n                    rs.close();\n                }\n            } catch (SQLException ex) {\n                LOG.error(\"clearResultSet error\", ex);","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/alibaba/druid/blob/fa8dc9912637a2f729eef9f55356621fec18d40e/core/src/main/java/com/alibaba/druid/pool/DruidPooledStatement.java#L165-L201","documentation":"Thrown by DruidPooledStatement.checkOpen() when the statement is closed AND the owning DruidPooledConnection has a non-null disableError. The chained disableError is the root cause that disabled the underlying connection (socket error, fatal SQLException, etc.), so this variant tells you the close was a consequence of connection invalidation rather than a normal close.","triggerScenarios":"Calling any statement method after closed==true, where the connection was disabled due to an underlying error: socket timeout, fatal DB error propagated to the pool, validation failure, or explicit pool.disableConnection(). checkOpen() is invoked by virtually every delegated Statement method.","commonSituations":"Reusing a Statement after the connection died mid-query; catching an exception from executeQuery but continuing to use the same Statement object; statement caching returning a stale handle after a DB restart.","solutions":["Stop using the Statement and Connection immediately; the disableError cause identifies the real failure.","Obtain a fresh connection and re-prepare the statement; do not attempt to recover the closed one.","Wrap DB calls in try-with-resources for Connection, Statement, and ResultSet so handles are always released in scope.","Inspect the chained Throwable (getCause()) to fix the underlying DB/network issue."],"exampleFix":"// before\nStatement st = conn.createStatement();\ntry { st.execute(bigQuery); } catch (SQLException ignore) {}\nst.executeQuery(nextSql); // throws 'statement is closed' with disableError\n\n// after\ntry (Connection c = ds.getConnection();\n     Statement st = c.createStatement()) {\n    st.execute(bigQuery);\n}","handlingStrategy":"try-catch","validationCode":"if (stmt.isClosed()) {\n    // the chained cause on the underlying conn identifies the failure;\n    // discard statement and connection\n    throw new IllegalStateException(\"statement already closed\");\n}","typeGuard":"public static boolean usable(Statement s) {\n    try { return s != null && !s.isClosed(); } catch (SQLException e) { return false; }\n}","tryCatchPattern":"try {\n    stmt.executeQuery(sql);\n} catch (SQLException e) {\n    if (\"statement is closed\".equals(e.getMessage()) && e.getCause() != null) {\n        log.warn(\"connection disabled by: {}\", e.getCause());\n    }\n    throw e;\n}","preventionTips":["Scope every Statement in try-with-resources.","When a query throws, treat both Statement and Connection as poisoned and discard them.","Inspect the chained disableError to root-cause the underlying DB failure."],"tags":["statement","closed-handle","connection-pool","jdbc"],"backgroundTag":null,"analyzedSha":"fa8dc9912637a2f729eef9f55356621fec18d40e","analyzedAt":"2026-08-14T04:55:06.789Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}