tursodatabase/turso · error · SQLException
statement is closed
Error message
statement is closed
What it means
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.
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
Example fix
// before
try (Statement stmt = conn.createStatement()) {
...
} // stmt closed here
stmt.closeOnCompletion(); // too late -> SQLException
// after
Statement stmt = conn.createStatement();
stmt.closeOnCompletion(); // configure right after creation
try (stmt) {
...
} Defensive patterns
Strategy: validation
Validate before calling
if (!stmt.isClosed()) {
stmt.closeOnCompletion();
} Try / catch
try {
stmt.closeOnCompletion();
} catch (SQLException e) {
if (e.getMessage() != null && e.getMessage().contains("statement is closed")) {
// already closed: nothing to configure
} else {
throw e;
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Statement is closed
- Invalid argument
- Query timeout must be greater than 0
- createBlob not supported
- createClob not supported
AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20).
Data as JSON: /api/errors/1c72a2d8d683f67c.
Report an issue: GitHub.
Appendix: source
Thrown at bindings/java/src/main/java/tech/turso/jdbc4/JDBC4Statement.java:432
public boolean isClosed() throws SQLException {
return this.closed;
}
@Override
public void setPoolable(boolean poolable) throws SQLException {
// TODO
}
@Override
public boolean isPoolable() throws SQLException {
// TODO
return false;
}
@Override
public void closeOnCompletion() throws SQLException {
if (closed) {
throw new SQLException("statement is closed");
}
closeOnCompletion = true;
}
/**
* Indicates whether the statement should be closed automatically when all its dependent result
* sets are closed.
*/
@Override
public boolean isCloseOnCompletion() throws SQLException {
if (closed) {
throw new SQLException("statement is closed");
}
return closeOnCompletion;
}
@Override
@SkipNullableCheckView on GitHub (pinned to 244cde92a7)