tursodatabase/turso · warning
Failed to rollback transaction during close
Error message
Failed to rollback transaction during close
What it means
TursoConnection.close() (bindings/java .../TursoConnection.java:83) checks isClosed(), then under transactionLock rolls back any open transaction via execute_internal("ROLLBACK") before closing. If that ROLLBACK throws, the SQLException is caught and logged at WARN level as "Failed to rollback transaction during close" through tech.turso.utils.Logger; inTransaction is cleared and the native connection is still closed via _close(connectionPtr). So this is a logged symptom, not a thrown error: the pending transaction could not be unwound, usually because the underlying engine already failed (I/O error, missing/unwritable file, poisoned connection).
Source
Thrown at bindings/java/src/main/java/tech/turso/core/TursoConnection.java:83
}
public String getUrl() {
return url;
}
public void close() throws SQLException {
if (isClosed()) {
return;
}
// Roll back any pending transaction before closing
synchronized (transactionLock) {
if (inTransaction) {
try {
executeInternal("ROLLBACK");
} catch (SQLException e) {
// Log but don't throw - we're closing anyway
logger.warn("Failed to rollback transaction during close", e);
} finally {
inTransaction = false;
}
}
}
this._close(this.connectionPtr);
this.closed = true;
}
private native void _close(long connectionPtr);
private native boolean _getAutoCommit(long connectionPtr);
public boolean isClosed() throws SQLException {
return closed;
}
View on GitHub (pinned to 244cde92a7)
Solutions
- Always commit or rollback explicitly in application finally blocks; treat close() as a last resort, not the transaction unwind.
- Read the WARN log's attached exception - it carries the SQLException with the underlying cause (I/O error, lock, disk full); fix that root cause.
- Check whether the connection was already poisoned by an earlier error; if so, the rollback failure is a symptom and the earlier failure is the real bug.
- Upgrade the Java bindings; close-time rollback handling may be improved in newer releases.
Example fix
// before: relying on close() to unwind the transaction
try (Connection conn = driver.connect(url, props)) {
conn.setAutoCommit(false);
stmt.executeUpdate("UPDATE t SET x = 1");
} // close() attempts rollback, logs WARN on failure
// after: explicit rollback before close
Connection conn = driver.connect(url, props);
try {
conn.setAutoCommit(false);
stmt.executeUpdate("UPDATE t SET x = 1");
conn.commit();
} catch (SQLException e) {
try { conn.rollback(); } catch (SQLException re) { log.warn("rollback failed", re); }
throw e;
} finally {
conn.close();
} Defensive patterns
Strategy: try-catch
Validate before calling
// Before closing: end the transaction explicitly so close() never needs to roll back.
if (!conn.isClosed() && !conn.getAutoCommit()) {
conn.rollback(); // or commit() - decide deliberately, not at close time
}
conn.close(); Try / catch
finally {
if (conn != null) {
try {
if (!conn.getAutoCommit()) conn.rollback();
} catch (SQLException rollbackEx) {
log.warn("rollback before close failed", rollbackEx); // capture the cause here
} finally {
try { conn.close(); } catch (SQLException closeEx) {
log.warn("close failed", closeEx);
}
}
}
} Prevention
- Always commit or rollback explicitly in application code; never delegate transaction cleanup to close().
- Treat any earlier SQLException on a connection as potentially poisoning it; validate with a trivial query before further use.
- Keep database files on reliable storage; verify disk space and mounts before shutdown sequences.
- Configure pools to reset transaction state on check-in (e.g. rollbackOnReturn) so pooled connections are never handed back mid-transaction.
When it happens
Trigger: Calling close() while a transaction is open (autoCommit=false with uncommitted writes) and the ROLLBACK itself fails - disk full, WAL on removed network storage, a prior fatal native error that already invalidated the connection, or close racing concurrent statement execution on the same connection.
Common situations: Application or connection-pool shutdown with uncommitted transactions, database files on removable/network mounts, disk exhaustion, code that swallows an earlier SQLException and closes anyway.
Related errors
- Cannot commit in autocommit mode.
- Cannot rollback in autocommit mode.
- Cannot change isolation level while transaction is active.
- Invalid transaction isolation level: {level}
- Exception while retrieving number of changes
AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20).
Data as JSON: /api/errors/e2d1bd3214e763d8.
Report an issue: GitHub.